Добавил трек и поле Примечание к Source
This commit is contained in:
@@ -45,7 +45,7 @@ class LoadExcelData(forms.Form):
|
|||||||
required=False,
|
required=False,
|
||||||
initial=False,
|
initial=False,
|
||||||
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
|
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
|
||||||
help_text="Если отмечено, точки не будут добавляться к объектам (Source)",
|
help_text="Если отмечено, точки не будут добавляться к объектам",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ class LoadCsvData(forms.Form):
|
|||||||
required=False,
|
required=False,
|
||||||
initial=False,
|
initial=False,
|
||||||
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
|
widget=forms.CheckboxInput(attrs={"class": "form-check-input"}),
|
||||||
help_text="Если отмечено, точки не будут добавляться к объектам (Source)",
|
help_text="Если отмечено, точки не будут добавляться к объектам",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -477,7 +477,7 @@ class SourceForm(forms.ModelForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Source
|
model = Source
|
||||||
fields = ['info', 'ownership']
|
fields = ['info', 'ownership', 'note']
|
||||||
widgets = {
|
widgets = {
|
||||||
'info': forms.Select(attrs={
|
'info': forms.Select(attrs={
|
||||||
'class': 'form-select',
|
'class': 'form-select',
|
||||||
@@ -487,10 +487,16 @@ class SourceForm(forms.ModelForm):
|
|||||||
'class': 'form-select',
|
'class': 'form-select',
|
||||||
'id': 'id_ownership',
|
'id': 'id_ownership',
|
||||||
}),
|
}),
|
||||||
|
'note': forms.Textarea(attrs={
|
||||||
|
'class': 'form-control',
|
||||||
|
'rows': "3",
|
||||||
|
'id': 'id_note',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
labels = {
|
labels = {
|
||||||
'info': 'Тип объекта',
|
'info': 'Тип объекта',
|
||||||
'ownership': 'Принадлежность объекта',
|
'ownership': 'Принадлежность объекта',
|
||||||
|
'note': 'Примечание'
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'info': 'Стационарные: координата усредняется. Подвижные: координата = последняя точка. При изменении типа координата пересчитывается автоматически.',
|
'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="Принадлежность объекта",
|
verbose_name="Принадлежность объекта",
|
||||||
help_text="Принадлежность объекта (страна, организация и т.д.)",
|
help_text="Принадлежность объекта (страна, организация и т.д.)",
|
||||||
)
|
)
|
||||||
|
note = models.TextField(
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
verbose_name="Примечание",
|
||||||
|
help_text="Дополнительное описание объекта",
|
||||||
|
)
|
||||||
confirm_at = models.DateTimeField(
|
confirm_at = models.DateTimeField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
|
|||||||
@@ -238,6 +238,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</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>
|
</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="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="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="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="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="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="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="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="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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</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: 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;">
|
<th scope="col" style="min-width: 120px;">
|
||||||
{% include 'mainapp/components/_sort_header.html' with field='created_at' label='Создано' current_sort=sort %}
|
{% include 'mainapp/components/_sort_header.html' with field='created_at' label='Создано' current_sort=sort %}
|
||||||
</th>
|
</th>
|
||||||
@@ -503,6 +506,7 @@
|
|||||||
<td>{{ source.coords_kupsat }}</td>
|
<td>{{ source.coords_kupsat }}</td>
|
||||||
<td>{{ source.coords_valid }}</td>
|
<td>{{ source.coords_valid }}</td>
|
||||||
<td>{{ source.coords_reference }}</td>
|
<td>{{ source.coords_reference }}</td>
|
||||||
|
<td>{{ source.note }}</td>
|
||||||
<td>{{ source.created_at|date:"d.m.Y H:i" }}</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.updated_at|date:"d.m.Y H:i" }}</td>
|
||||||
<td>{{ source.confirm_at|date:"d.m.Y H:i"|default:"-" }}</td>
|
<td>{{ source.confirm_at|date:"d.m.Y H:i"|default:"-" }}</td>
|
||||||
@@ -1122,6 +1126,7 @@ function initColumnVisibility() {
|
|||||||
// Default state: hide Создано and Обновлено columns
|
// Default state: hide Создано and Обновлено columns
|
||||||
const createdAtCheckbox = document.querySelector('input[data-column="11"]');
|
const createdAtCheckbox = document.querySelector('input[data-column="11"]');
|
||||||
const updatedAtCheckbox = document.querySelector('input[data-column="12"]');
|
const updatedAtCheckbox = document.querySelector('input[data-column="12"]');
|
||||||
|
const noteCheckbox = document.querySelector('input[data-column="13"]');
|
||||||
|
|
||||||
if (createdAtCheckbox) {
|
if (createdAtCheckbox) {
|
||||||
createdAtCheckbox.checked = false;
|
createdAtCheckbox.checked = false;
|
||||||
@@ -1133,6 +1138,11 @@ function initColumnVisibility() {
|
|||||||
toggleColumnWithoutSave(updatedAtCheckbox);
|
toggleColumnWithoutSave(updatedAtCheckbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (noteCheckbox) {
|
||||||
|
noteCheckbox.checked = false;
|
||||||
|
toggleColumnWithoutSave(noteCheckbox);
|
||||||
|
}
|
||||||
|
|
||||||
// Save initial state
|
// Save initial state
|
||||||
saveColumnVisibility();
|
saveColumnVisibility();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@
|
|||||||
<script src="{% static 'leaflet/leaflet.js' %}"></script>
|
<script src="{% static 'leaflet/leaflet.js' %}"></script>
|
||||||
<script src="{% static 'leaflet-measure/leaflet-measure.ru.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="{% 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>
|
<script>
|
||||||
// Инициализация карты
|
// Инициализация карты
|
||||||
@@ -119,6 +120,23 @@
|
|||||||
|
|
||||||
var sourceOverlays = [];
|
var sourceOverlays = [];
|
||||||
var glPointLayers = [];
|
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 %}
|
{% for group in groups %}
|
||||||
@@ -138,14 +156,31 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
// Это точка ГЛ
|
// Это точка ГЛ
|
||||||
var pointName = "{{ point_data.name|escapejs }}";
|
var pointName = "{{ point_data.name|escapejs }}";
|
||||||
var marker = L.marker([{{ point_data.point.1|safe }}, {{ point_data.point.0|safe }}], {
|
var pointCoords = [{{ point_data.point.1|safe }}, {{ point_data.point.0|safe }}];
|
||||||
icon: groupIcon
|
var pointNumber = {{ forloop.counter }};
|
||||||
}).bindPopup(pointName + '<br>' + "{{ point_data.frequency|escapejs }}");
|
|
||||||
|
// Определяем цвет маркера: первый - зеленый, последний - оранжевый, остальные - обычный
|
||||||
|
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);
|
groupLayer.addLayer(marker);
|
||||||
|
glPointsGroupLayer.addLayer(marker); // Also add to GL points group layer
|
||||||
|
|
||||||
|
// Сохраняем координаты для построения трека
|
||||||
|
glPointCoordinates.push(pointCoords);
|
||||||
|
|
||||||
// Добавляем каждую точку ГЛ отдельно в список
|
// Добавляем каждую точку ГЛ отдельно в список
|
||||||
glPointLayers.push({
|
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
|
layer: marker
|
||||||
});
|
});
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -158,8 +193,76 @@
|
|||||||
layer: groupLayer
|
layer: groupLayer
|
||||||
});
|
});
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
// Добавляем слой группы на карту
|
||||||
|
{% if group.color in 'blue,orange,green,violet' %}
|
||||||
|
groupLayer.addTo(map);
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% 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 = [];
|
var treeOverlays = [];
|
||||||
|
|
||||||
@@ -177,7 +280,15 @@
|
|||||||
label: "Точки ГЛ",
|
label: "Точки ГЛ",
|
||||||
selectAllCheckbox: true,
|
selectAllCheckbox: true,
|
||||||
children: glPointLayers,
|
children: glPointLayers,
|
||||||
layer: L.layerGroup()
|
layer: glPointsGroupLayer
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем слой трека в контрол
|
||||||
|
if (glPointCoordinates.length > 1) {
|
||||||
|
treeOverlays.push({
|
||||||
|
label: "Трек между точками ГЛ",
|
||||||
|
layer: trackLayer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +335,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
// Точки ГЛ (все одним цветом)
|
// Точки ГЛ
|
||||||
{% for group in groups %}
|
{% for group in groups %}
|
||||||
{% if group.color not in 'blue,orange,green,violet' %}
|
{% if group.color not in 'blue,orange,green,violet' %}
|
||||||
div.innerHTML += '<div class="legend-section"><div class="legend-section-title">Точки ГЛ:</div></div>';
|
div.innerHTML += '<div class="legend-section"><div class="legend-section-title">Точки ГЛ:</div></div>';
|
||||||
@@ -237,6 +348,32 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% 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;
|
return div;
|
||||||
};
|
};
|
||||||
legend.addTo(map);
|
legend.addTo(map);
|
||||||
|
|||||||
@@ -671,6 +671,7 @@ class SourceListView(LoginRequiredMixin, View):
|
|||||||
'has_lyngsat': has_lyngsat,
|
'has_lyngsat': has_lyngsat,
|
||||||
'lyngsat_id': lyngsat_id,
|
'lyngsat_id': lyngsat_id,
|
||||||
'marks': marks_data,
|
'marks': marks_data,
|
||||||
|
'note': source.note if source.note else '-'
|
||||||
})
|
})
|
||||||
|
|
||||||
# Prepare context for template
|
# Prepare context for template
|
||||||
|
|||||||
Reference in New Issue
Block a user