176 lines
5.7 KiB
React
176 lines
5.7 KiB
React
import React, { useState, useEffect } from 'react';
|
||
import { Link } from 'react-router-dom';
|
||
import axios from 'axios';
|
||
import './CasesList.css';
|
||
|
||
const CasesList = () => {
|
||
const [cases, setCases] = useState([]);
|
||
const [loading, setLoading] = useState(true);
|
||
const [error, setError] = useState(null);
|
||
const [filters, setFilters] = useState({
|
||
gender: '',
|
||
ageFrom: '',
|
||
ageTo: '',
|
||
diagnosis: '',
|
||
psychotype: ''
|
||
});
|
||
|
||
useEffect(() => {
|
||
fetchCases();
|
||
}, [filters]);
|
||
|
||
const fetchCases = async () => {
|
||
setLoading(true);
|
||
try {
|
||
const params = new URLSearchParams();
|
||
if (filters.gender) params.append('gender', filters.gender);
|
||
if (filters.ageFrom) params.append('age_from', filters.ageFrom);
|
||
if (filters.ageTo) params.append('age_to', filters.ageTo);
|
||
if (filters.diagnosis) params.append('diagnosis', filters.diagnosis);
|
||
if (filters.psychotype) params.append('psychotype', filters.psychotype);
|
||
|
||
const response = await axios.get(`/api/v1/cases?${params}`);
|
||
setCases(response.data);
|
||
setError(null);
|
||
} catch (err) {
|
||
setError('Ошибка загрузки данных');
|
||
console.error(err);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
const formatDate = (dateString) => {
|
||
if (!dateString) return 'Не указано';
|
||
return new Date(dateString).toLocaleDateString('ru-RU');
|
||
};
|
||
|
||
const getPsychotypeLabel = (psychotype) => {
|
||
const labels = {
|
||
'explorer': 'Исследователь',
|
||
'cautious': 'Осторожный',
|
||
'passive': 'Пассивный',
|
||
'panicker': 'Паникёр'
|
||
};
|
||
return labels[psychotype] || psychotype;
|
||
};
|
||
|
||
return (
|
||
<div className="cases-list">
|
||
<div className="cases-header">
|
||
<h1>Карточки пропавших</h1>
|
||
<div className="header-actions">
|
||
<button className="btn-primary" onClick={fetchCases}>
|
||
🔄 Обновить
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Фильтры */}
|
||
<div className="filters-panel">
|
||
<div className="filter-group">
|
||
<label>Пол:</label>
|
||
<select value={filters.gender} onChange={(e) => setFilters({...filters, gender: e.target.value})}>
|
||
<option value="">Все</option>
|
||
<option value="male">Мужской</option>
|
||
<option value="female">Женский</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div className="filter-group">
|
||
<label>Возраст от:</label>
|
||
<input
|
||
type="number"
|
||
value={filters.ageFrom}
|
||
onChange={(e) => setFilters({...filters, ageFrom: e.target.value})}
|
||
placeholder="0"
|
||
/>
|
||
</div>
|
||
|
||
<div className="filter-group">
|
||
<label>до:</label>
|
||
<input
|
||
type="number"
|
||
value={filters.ageTo}
|
||
onChange={(e) => setFilters({...filters, ageTo: e.target.value})}
|
||
placeholder="100"
|
||
/>
|
||
</div>
|
||
|
||
<div className="filter-group">
|
||
<label>Диагноз:</label>
|
||
<select value={filters.diagnosis} onChange={(e) => setFilters({...filters, diagnosis: e.target.value})}>
|
||
<option value="">Все</option>
|
||
<option value="РАС">РАС</option>
|
||
<option value="эпилепсия">Эпилепсия</option>
|
||
<option value="СДВГ">СДВГ</option>
|
||
<option value="деменция">Деменция</option>
|
||
</select>
|
||
</div>
|
||
|
||
<button className="btn-secondary" onClick={() => setFilters({
|
||
gender: '', ageFrom: '', ageTo: '', diagnosis: '', psychotype: ''
|
||
})}>
|
||
Сбросить фильтры
|
||
</button>
|
||
</div>
|
||
|
||
{/* Таблица */}
|
||
{loading ? (
|
||
<div className="loading-state">Загрузка...</div>
|
||
) : error ? (
|
||
<div className="error-state">{error}</div>
|
||
) : cases.length === 0 ? (
|
||
<div className="empty-state">Карточки не найдены</div>
|
||
) : (
|
||
<div className="table-container">
|
||
<table className="cases-table">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>Возраст</th>
|
||
<th>Пол</th>
|
||
<th>Диагнозы</th>
|
||
<th>Психотип</th>
|
||
<th>Дата создания</th>
|
||
<th>Действия</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{cases.map(caseItem => (
|
||
<tr key={caseItem.id}>
|
||
<td>{caseItem.id}</td>
|
||
<td>{caseItem.age || '—'}</td>
|
||
<td>{caseItem.gender === 'male' ? 'М' : caseItem.gender === 'female' ? 'Ж' : '—'}</td>
|
||
<td>
|
||
{caseItem.diagnosis_type && caseItem.diagnosis_type.length > 0
|
||
? caseItem.diagnosis_type.join(', ')
|
||
: '—'}
|
||
</td>
|
||
<td>
|
||
{caseItem.psychotype_result
|
||
? <span className="psychotype-badge">{getPsychotypeLabel(caseItem.psychotype_result)}</span>
|
||
: '—'}
|
||
</td>
|
||
<td>{formatDate(caseItem.created_at)}</td>
|
||
<td>
|
||
<Link to={`/admin/cases/${caseItem.id}`} className="btn-link">
|
||
Подробнее
|
||
</Link>
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
)}
|
||
|
||
<div className="cases-footer">
|
||
<p>Всего карточек: <strong>{cases.length}</strong></p>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default CasesList;
|