Добавил трек и поле Примечание к Source
This commit is contained in:
@@ -45,7 +45,7 @@ class LoadExcelData(forms.Form):
|
||||
required=False,
|
||||
initial=False,
|
||||
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
|
||||
help_text="Если отмечено, точки не будут добавляться к объектам (Source)",
|
||||
help_text="Если отмечено, точки не будут добавляться к объектам",
|
||||
)
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class LoadCsvData(forms.Form):
|
||||
required=False,
|
||||
initial=False,
|
||||
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
|
||||
help_text="Если отмечено, точки не будут добавляться к объектам (Source)",
|
||||
help_text="Если отмечено, точки не будут добавляться к объектам",
|
||||
)
|
||||
|
||||
|
||||
@@ -477,7 +477,7 @@ class SourceForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = Source
|
||||
fields = ['info', 'ownership']
|
||||
fields = ['info', 'ownership', 'note']
|
||||
widgets = {
|
||||
'info': forms.Select(attrs={
|
||||
'class': 'form-select',
|
||||
@@ -487,10 +487,16 @@ class SourceForm(forms.ModelForm):
|
||||
'class': 'form-select',
|
||||
'id': 'id_ownership',
|
||||
}),
|
||||
'note': forms.Textarea(attrs={
|
||||
'class': 'form-control',
|
||||
'rows': "3",
|
||||
'id': 'id_note',
|
||||
})
|
||||
}
|
||||
labels = {
|
||||
'info': 'Тип объекта',
|
||||
'ownership': 'Принадлежность объекта',
|
||||
'note': 'Примечание'
|
||||
}
|
||||
help_texts = {
|
||||
'info': 'Стационарные: координата усредняется. Подвижные: координата = последняя точка. При изменении типа координата пересчитывается автоматически.',
|
||||
|
||||
18
dbapp/mainapp/migrations/0014_source_note.py
Normal file
18
dbapp/mainapp/migrations/0014_source_note.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-25 12:46
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mainapp', '0013_add_is_automatic_to_objitem'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='source',
|
||||
name='note',
|
||||
field=models.TextField(blank=True, help_text='Дополнительное описание объекта', null=True, verbose_name='Примечание'),
|
||||
),
|
||||
]
|
||||
@@ -491,6 +491,12 @@ class Source(models.Model):
|
||||
verbose_name="Принадлежность объекта",
|
||||
help_text="Принадлежность объекта (страна, организация и т.д.)",
|
||||
)
|
||||
note = models.TextField(
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name="Примечание",
|
||||
help_text="Дополнительное описание объекта",
|
||||
)
|
||||
confirm_at = models.DateTimeField(
|
||||
null=True,
|
||||
blank=True,
|
||||
|
||||
@@ -238,6 +238,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="mb-3">
|
||||
<label for="id_ownership" class="form-label">{{ form.note.label }}:</label>
|
||||
{{ form.note }}
|
||||
{% if form.note.errors %}
|
||||
<div class="invalid-feedback d-block">
|
||||
{{ form.note.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Блок с картой -->
|
||||
|
||||
@@ -148,11 +148,13 @@
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="8" checked onchange="toggleColumn(this)"> Координаты Кубсата</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="9" checked onchange="toggleColumn(this)"> Координаты визуального наблюдения</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="10" checked onchange="toggleColumn(this)"> Координаты справочные</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="11" onchange="toggleColumn(this)"> Создано</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="12" onchange="toggleColumn(this)"> Обновлено</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="13" checked onchange="toggleColumn(this)"> Дата подтверждения</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="14" checked onchange="toggleColumn(this)"> Последний сигнал</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="15" checked onchange="toggleColumn(this)"> Действия</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="11" checked onchange="toggleColumn(this)"> Примечание</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="12" onchange="toggleColumn(this)"> Создано</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="13" onchange="toggleColumn(this)"> Обновлено</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="14" checked onchange="toggleColumn(this)"> Дата подтверждения</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="15" checked onchange="toggleColumn(this)"> Последний сигнал</label></li>
|
||||
<li><label class="dropdown-item"><input type="checkbox" class="column-toggle" data-column="16" checked onchange="toggleColumn(this)"> Действия</label></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -457,6 +459,7 @@
|
||||
<th scope="col" style="min-width: 150px;">Координаты Кубсата</th>
|
||||
<th scope="col" style="min-width: 150px;">Координаты визуального наблюдения</th>
|
||||
<th scope="col" style="min-width: 150px;">Координаты справочные</th>
|
||||
<th scope="col" style="min-width: 120px;">Примечание</th>
|
||||
<th scope="col" style="min-width: 120px;">
|
||||
{% include 'mainapp/components/_sort_header.html' with field='created_at' label='Создано' current_sort=sort %}
|
||||
</th>
|
||||
@@ -503,6 +506,7 @@
|
||||
<td>{{ source.coords_kupsat }}</td>
|
||||
<td>{{ source.coords_valid }}</td>
|
||||
<td>{{ source.coords_reference }}</td>
|
||||
<td>{{ source.note }}</td>
|
||||
<td>{{ source.created_at|date:"d.m.Y H:i" }}</td>
|
||||
<td>{{ source.updated_at|date:"d.m.Y H:i" }}</td>
|
||||
<td>{{ source.confirm_at|date:"d.m.Y H:i"|default:"-" }}</td>
|
||||
@@ -1122,6 +1126,7 @@ function initColumnVisibility() {
|
||||
// Default state: hide Создано and Обновлено columns
|
||||
const createdAtCheckbox = document.querySelector('input[data-column="11"]');
|
||||
const updatedAtCheckbox = document.querySelector('input[data-column="12"]');
|
||||
const noteCheckbox = document.querySelector('input[data-column="13"]');
|
||||
|
||||
if (createdAtCheckbox) {
|
||||
createdAtCheckbox.checked = false;
|
||||
@@ -1133,6 +1138,11 @@ function initColumnVisibility() {
|
||||
toggleColumnWithoutSave(updatedAtCheckbox);
|
||||
}
|
||||
|
||||
if (noteCheckbox) {
|
||||
noteCheckbox.checked = false;
|
||||
toggleColumnWithoutSave(noteCheckbox);
|
||||
}
|
||||
|
||||
// Save initial state
|
||||
saveColumnVisibility();
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
<script src="{% static 'leaflet/leaflet.js' %}"></script>
|
||||
<script src="{% static 'leaflet-measure/leaflet-measure.ru.js' %}"></script>
|
||||
<script src="{% static 'leaflet-tree/L.Control.Layers.Tree.js' %}"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/leaflet-polylinedecorator@1.6.0/dist/leaflet.polylineDecorator.min.js"></script>
|
||||
|
||||
<script>
|
||||
// Инициализация карты
|
||||
@@ -119,6 +120,23 @@
|
||||
|
||||
var sourceOverlays = [];
|
||||
var glPointLayers = [];
|
||||
var glPointCoordinates = [];
|
||||
var glPointsData = [];
|
||||
var trackLayer = L.layerGroup(); // Layer group for track and related elements
|
||||
var glPointsGroupLayer = L.layerGroup(); // Layer group specifically for GL points
|
||||
|
||||
// Сначала собираем все данные о точках ГЛ
|
||||
{% for group in groups %}
|
||||
{% for point_data in group.points %}
|
||||
{% if not point_data.source_id %}
|
||||
glPointsData.push({
|
||||
name: "{{ point_data.name|escapejs }}",
|
||||
frequency: "{{ point_data.frequency|escapejs }}",
|
||||
coords: [{{ point_data.point.1|safe }}, {{ point_data.point.0|safe }}]
|
||||
});
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
// Создаём слои для координат объекта и точек ГЛ
|
||||
{% for group in groups %}
|
||||
@@ -138,14 +156,31 @@
|
||||
{% else %}
|
||||
// Это точка ГЛ
|
||||
var pointName = "{{ point_data.name|escapejs }}";
|
||||
var marker = L.marker([{{ point_data.point.1|safe }}, {{ point_data.point.0|safe }}], {
|
||||
icon: groupIcon
|
||||
}).bindPopup(pointName + '<br>' + "{{ point_data.frequency|escapejs }}");
|
||||
var pointCoords = [{{ point_data.point.1|safe }}, {{ point_data.point.0|safe }}];
|
||||
var pointNumber = {{ forloop.counter }};
|
||||
|
||||
// Определяем цвет маркера: первый - зеленый, последний - оранжевый, остальные - обычный
|
||||
var markerIcon;
|
||||
if (pointNumber === 1) {
|
||||
markerIcon = getColorIcon('green');
|
||||
} else if (pointNumber === glPointsData.length) {
|
||||
markerIcon = getColorIcon('orange');
|
||||
} else {
|
||||
markerIcon = groupIcon;
|
||||
}
|
||||
|
||||
var marker = L.marker(pointCoords, {
|
||||
icon: markerIcon
|
||||
}).bindPopup(pointNumber + '. ' + pointName + '<br>' + "{{ point_data.frequency|escapejs }}");
|
||||
groupLayer.addLayer(marker);
|
||||
glPointsGroupLayer.addLayer(marker); // Also add to GL points group layer
|
||||
|
||||
// Сохраняем координаты для построения трека
|
||||
glPointCoordinates.push(pointCoords);
|
||||
|
||||
// Добавляем каждую точку ГЛ отдельно в список
|
||||
glPointLayers.push({
|
||||
label: "{{ forloop.counter }} - {{ point_data.name|escapejs }} ({{ point_data.frequency|escapejs }})",
|
||||
label: pointNumber + " - {{ point_data.name|escapejs }} ({{ point_data.frequency|escapejs }})",
|
||||
layer: marker
|
||||
});
|
||||
{% endif %}
|
||||
@@ -158,8 +193,76 @@
|
||||
layer: groupLayer
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
// Добавляем слой группы на карту
|
||||
{% if group.color in 'blue,orange,green,violet' %}
|
||||
groupLayer.addTo(map);
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
// Создаём трек между точками ГЛ с номерами на сегментах
|
||||
if (glPointCoordinates.length > 1) {
|
||||
// Создаём отдельные сегменты линий между точками
|
||||
for (var i = 0; i < glPointCoordinates.length - 1; i++) {
|
||||
var segmentNumber = i + 1;
|
||||
|
||||
// Создаем линию с стрелкой
|
||||
var segment = L.polyline([glPointCoordinates[i], glPointCoordinates[i + 1]], {
|
||||
color: 'blue',
|
||||
weight: 3,
|
||||
opacity: 0.7
|
||||
});
|
||||
trackLayer.addLayer(segment);
|
||||
|
||||
// Добавляем стрелку через декоратор
|
||||
setTimeout(function(seg, segLayer, num) {
|
||||
return function() {
|
||||
var decorator = L.polylineDecorator(seg, {
|
||||
patterns: [
|
||||
{
|
||||
offset: '65%',
|
||||
repeat: 0,
|
||||
symbol: L.Symbol.arrowHead({
|
||||
pixelSize: 15,
|
||||
polygon: false,
|
||||
pathOptions: {
|
||||
stroke: true,
|
||||
color: 'blue',
|
||||
weight: 3,
|
||||
opacity: 0.7
|
||||
}
|
||||
})
|
||||
}
|
||||
]
|
||||
});
|
||||
segLayer.addLayer(decorator);
|
||||
};
|
||||
}(segment, trackLayer, segmentNumber), 100);
|
||||
|
||||
// Вычисляем центр сегмента для размещения номера
|
||||
var midLat = (glPointCoordinates[i][0] + glPointCoordinates[i + 1][0]) / 2;
|
||||
var midLng = (glPointCoordinates[i][1] + glPointCoordinates[i + 1][1]) / 2;
|
||||
|
||||
// Добавляем номер сегмента
|
||||
var segmentIcon = L.divIcon({
|
||||
className: 'segment-label',
|
||||
html: '<div style="background: rgba(0, 0, 255, 0.9); color: white; border: 2px solid white; border-radius: 50%; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 14px; box-shadow: 0 2px 4px rgba(0,0,0,0.4);">' + segmentNumber + '</div>',
|
||||
iconSize: [28, 28],
|
||||
iconAnchor: [14, 14]
|
||||
});
|
||||
var segmentMarker = L.marker([midLat, midLng], { icon: segmentIcon });
|
||||
trackLayer.addLayer(segmentMarker);
|
||||
}
|
||||
|
||||
// Добавляем слой трека на карту
|
||||
trackLayer.addTo(map);
|
||||
}
|
||||
|
||||
// Добавляем GL точки на карту
|
||||
if (glPointLayers.length > 0) {
|
||||
glPointsGroupLayer.addTo(map);
|
||||
}
|
||||
|
||||
// Создаём иерархию
|
||||
var treeOverlays = [];
|
||||
|
||||
@@ -177,7 +280,15 @@
|
||||
label: "Точки ГЛ",
|
||||
selectAllCheckbox: true,
|
||||
children: glPointLayers,
|
||||
layer: L.layerGroup()
|
||||
layer: glPointsGroupLayer
|
||||
});
|
||||
}
|
||||
|
||||
// Добавляем слой трека в контрол
|
||||
if (glPointCoordinates.length > 1) {
|
||||
treeOverlays.push({
|
||||
label: "Трек между точками ГЛ",
|
||||
layer: trackLayer
|
||||
});
|
||||
}
|
||||
|
||||
@@ -224,7 +335,7 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
// Точки ГЛ (все одним цветом)
|
||||
// Точки ГЛ
|
||||
{% for group in groups %}
|
||||
{% if group.color not in 'blue,orange,green,violet' %}
|
||||
div.innerHTML += '<div class="legend-section"><div class="legend-section-title">Точки ГЛ:</div></div>';
|
||||
@@ -237,6 +348,32 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
// Добавляем информацию о треке
|
||||
if (glPointCoordinates.length > 1) {
|
||||
div.innerHTML += '<div class="legend-section"><div class="legend-section-title">Трек между точками:</div></div>';
|
||||
div.innerHTML += `
|
||||
<div class="legend-item">
|
||||
<div style="width: 18px; height: 3px; background: blue; margin-right: 6px;"></div>
|
||||
<span>Соединительная линия</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Добавляем информацию о специальных точках
|
||||
if (glPointCoordinates.length > 1) {
|
||||
div.innerHTML += '<div class="legend-section"><div class="legend-section-title">Специальные точки:</div></div>';
|
||||
div.innerHTML += `
|
||||
<div class="legend-item">
|
||||
<div class="legend-marker" style="background-image: url('{% static "leaflet-markers/img/marker-icon-green.png" %}');"></div>
|
||||
<span>Первая точка</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-marker" style="background-image: url('{% static "leaflet-markers/img/marker-icon-orange.png" %}');"></div>
|
||||
<span>Последняя точка</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return div;
|
||||
};
|
||||
legend.addTo(map);
|
||||
|
||||
@@ -671,6 +671,7 @@ class SourceListView(LoginRequiredMixin, View):
|
||||
'has_lyngsat': has_lyngsat,
|
||||
'lyngsat_id': lyngsat_id,
|
||||
'marks': marks_data,
|
||||
'note': source.note if source.note else '-'
|
||||
})
|
||||
|
||||
# Prepare context for template
|
||||
|
||||
Reference in New Issue
Block a user