департмент

This commit is contained in:
gorbenko.pavel
2026-07-29 16:09:19 +05:00
parent 3ed399becc
commit ab5793b1a9
2 changed files with 23 additions and 6 deletions
@@ -328,6 +328,7 @@ export const RoutesScreen: React.FC<IRoutesScreenProps> = ({ api, dictionary, on
clearLabel="Без отдела (маршрут по умолчанию)"
placeholder="Без отдела (маршрут по умолчанию)"
searchPlaceholder="Поиск по названию отдела..."
emptyMessage="У выбранной компании нет отделов в справочнике"
onChange={departmentId => setForm({ ...form, departmentId })}
/>
</Field>
@@ -20,6 +20,8 @@ export interface ISearchableSelectProps {
/** Показывать пункт «очистить» — для необязательных полей. */
allowClear?: boolean;
clearLabel?: string;
/** Текст, когда список опций пуст (не результат поиска, а вообще нечего выбирать). */
emptyMessage?: string;
}
export const SearchableSelect: React.FC<ISearchableSelectProps> = ({
@@ -31,25 +33,35 @@ export const SearchableSelect: React.FC<ISearchableSelectProps> = ({
disabled,
loading,
allowClear,
clearLabel = 'Не выбрано'
clearLabel = 'Не выбрано',
emptyMessage = 'Ничего не найдено'
}) => {
const [open, setOpen] = React.useState(false);
const [query, setQuery] = React.useState('');
const rootRef = React.useRef<HTMLDivElement>(null);
const searchRef = React.useRef<HTMLInputElement>(null);
const selected = options.filter(o => o.value === value)[0];
// Сохранённое значение может отсутствовать в справочнике (запись удалили в 1С
// или она не проходит текущий фильтр). Показать в этом случае плейсхолдер —
// значит соврать, будто поле пустое, и затереть значение при сохранении.
// Поэтому подмешиваем недостающую опцию явным образом.
const effectiveOptions = React.useMemo(() => {
if (!value || options.some(o => o.value === value)) return options;
return [{ value, label: value, sublabel: 'Нет в справочнике' }, ...options];
}, [options, value]);
const selected = effectiveOptions.filter(o => o.value === value)[0];
// Поиск на клиенте: справочник целиком уже загружен, отделов ~700 —
// фильтровать в памяти дешевле, чем ходить на сервер на каждый символ.
const filtered = React.useMemo(() => {
const q = query.trim().toLowerCase();
if (!q) return options;
return options.filter(o =>
if (!q) return effectiveOptions;
return effectiveOptions.filter(o =>
o.label.toLowerCase().indexOf(q) !== -1 ||
(o.sublabel ? o.sublabel.toLowerCase().indexOf(q) !== -1 : false)
);
}, [options, query]);
}, [effectiveOptions, query]);
React.useEffect(() => {
if (!open) return;
@@ -110,7 +122,11 @@ export const SearchableSelect: React.FC<ISearchableSelectProps> = ({
onChange={e => setQuery(e.target.value)}
/>
<div className={styles.list}>
{filtered.length === 0 && <div className={styles.empty}>Ничего не найдено</div>}
{filtered.length === 0 && (
<div className={styles.empty}>
{effectiveOptions.length === 0 ? emptyMessage : 'Ничего не найдено'}
</div>
)}
{filtered.map(opt => (
<button
type="button"