Import Vector lab project
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user