UI: справочники типа места находки / кто нашёл / направление — единые селекты

- constants.js: LOCATION_TYPES (дорога/тропа/лес/дом-стройка/вода-берег/поле/
  не указано), WHO_FOUND_TYPES, FOUND_DIRECTIONS (8 румбов).
- Модал завершения поиска: тип места, кто нашёл, направление — селекты вместо
  свободного ввода (данные пригодны для матобработки архива без нормализации).
- Архив /admin (ClosedCases): «Кто нашёл» → тот же селект; LOCATION_TYPES
  вынесен в общий модуль.
This commit is contained in:
2026-09-09 22:08:25 +03:00
parent 91fe8358ac
commit 6e9dfe8a6f
3 changed files with 26 additions and 7 deletions
+7
View File
@@ -0,0 +1,7 @@
// Единый справочник для архива (/admin завершённые) и завершения операции:
export const LOCATION_TYPES = ['дорога', 'тропа', 'лес', 'дом/стройка', 'вода/берег', 'открытое поле', 'не указано'];
// Кто нашёл (справочник для завершения поиска и архива):
export const WHO_FOUND_TYPES = ['поисковая группа', 'кинолог с собакой', 'местные жители', 'полицейский', 'сам вышел', 'ВОХР/охрана', 'другое'];
export const FOUND_DIRECTIONS = ['С', 'СВ', 'В', 'ЮВ', 'Ю', 'ЮЗ', 'З', 'СЗ'];
+5 -3
View File
@@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { apiJson } from '../api/client'; import { apiJson } from '../api/client';
import { LOCATION_TYPES, WHO_FOUND_TYPES } from '../constants';
import './ClosedCases.css'; import './ClosedCases.css';
const DIAGNOSIS_OPTIONS = ['РАС', 'эпилепсия', 'СДВГ', 'ЗПР']; const DIAGNOSIS_OPTIONS = ['РАС', 'эпилепсия', 'СДВГ', 'ЗПР'];
@@ -12,7 +13,6 @@ const TRANSPORT_OPTIONS = [
]; ];
const SEASON_OPTIONS = ['зима', 'весна', 'лето', 'осень']; const SEASON_OPTIONS = ['зима', 'весна', 'лето', 'осень'];
const WEATHER_OPTIONS = ['нет', 'дождь', 'ливень', 'туман', 'снег', 'жара']; const WEATHER_OPTIONS = ['нет', 'дождь', 'ливень', 'туман', 'снег', 'жара'];
const LOCATION_TYPES = ['дорога', 'тропа', 'лес', 'дом/стройка', 'вода/берег', 'открытое поле', 'не указано'];
const EMPTY_FORM = { const EMPTY_FORM = {
age_years: '', age_years: '',
@@ -283,8 +283,10 @@ export default function ClosedCases() {
</select> </select>
</Field> </Field>
<Field label="Кто нашёл"> <Field label="Кто нашёл">
<input value={form.who_found} placeholder="группа, кинолог, местные…" <select value={form.who_found} onChange={(e) => update('who_found', e.target.value)}>
onChange={(e) => update('who_found', e.target.value)} /> <option value="">—</option>
{WHO_FOUND_TYPES.map((o) => <option key={o} value={o}>{o}</option>)}
</select>
</Field> </Field>
<Field label="Длительность поиска, ч"> <Field label="Длительность поиска, ч">
<input type="number" step="0.5" value={form.search_duration_hours} <input type="number" step="0.5" value={form.search_duration_hours}
+14 -4
View File
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import SearchMap from '../../components/SearchMap'; import SearchMap from '../../components/SearchMap';
import { apiFetch } from "../../api/client"; import { apiFetch } from "../../api/client";
import { LOCATION_TYPES, WHO_FOUND_TYPES, FOUND_DIRECTIONS } from "../../constants";
import "./AnalysisResult.css"; import "./AnalysisResult.css";
const GENDER_LABEL = { m: 'М', f: 'Ж' }; const GENDER_LABEL = { m: 'М', f: 'Ж' };
@@ -457,17 +458,26 @@ const AnalysisResult = () => {
<label>Дистанция, км <label>Дистанция, км
<input type="number" step="0.1" value={completeForm.found_distance_km} onChange={(e) => setCompleteForm({ ...completeForm, found_distance_km: e.target.value })} /> <input type="number" step="0.1" value={completeForm.found_distance_km} onChange={(e) => setCompleteForm({ ...completeForm, found_distance_km: e.target.value })} />
</label> </label>
<label>Направление (N/NE/E/...) <label>Направление от ТНП
<input value={completeForm.found_direction} onChange={(e) => setCompleteForm({ ...completeForm, found_direction: e.target.value })} /> <select value={completeForm.found_direction} onChange={(e) => setCompleteForm({ ...completeForm, found_direction: e.target.value })}>
<option value="">—</option>
{FOUND_DIRECTIONS.map((o) => <option key={o} value={o}>{o}</option>)}
</select>
</label> </label>
<label>Кто нашёл <label>Кто нашёл
<input value={completeForm.who_found} onChange={(e) => setCompleteForm({ ...completeForm, who_found: e.target.value })} /> <select value={completeForm.who_found} onChange={(e) => setCompleteForm({ ...completeForm, who_found: e.target.value })}>
<option value="">—</option>
{WHO_FOUND_TYPES.map((o) => <option key={o} value={o}>{o}</option>)}
</select>
</label> </label>
<label>Длительность поиска, ч <label>Длительность поиска, ч
<input type="number" step="0.5" value={completeForm.search_duration_hours} onChange={(e) => setCompleteForm({ ...completeForm, search_duration_hours: e.target.value })} /> <input type="number" step="0.5" value={completeForm.search_duration_hours} onChange={(e) => setCompleteForm({ ...completeForm, search_duration_hours: e.target.value })} />
</label> </label>
<label>Тип места находки <label>Тип места находки
<input value={completeForm.found_location_type} onChange={(e) => setCompleteForm({ ...completeForm, found_location_type: e.target.value })} /> <select value={completeForm.found_location_type} onChange={(e) => setCompleteForm({ ...completeForm, found_location_type: e.target.value })}>
<option value="">—</option>
{LOCATION_TYPES.map((o) => <option key={o} value={o}>{o}</option>)}
</select>
</label> </label>
</div> </div>
{completeResult && ( {completeResult && (