AURORA-1989: номер статьи, сортировка и поиск в окне выбора расхода

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-11-08 22:38:04 +04:00
parent 321943db56
commit b87b12f980
3 changed files with 52 additions and 2 deletions

View File

@ -5,6 +5,7 @@ import { ExpenseItemApi } from '../../../api/expense-item';
import { DangerOutlinedButton, PrimaryButton } from '../../common/Buttons/Buttons'; import { DangerOutlinedButton, PrimaryButton } from '../../common/Buttons/Buttons';
import { HeaderContainer, ModalBackdrop, ModalContainer, ModalTitle } from '../../common/Modal/ModalStyled'; import { HeaderContainer, ModalBackdrop, ModalContainer, ModalTitle } from '../../common/Modal/ModalStyled';
import { Cancel } from '../../common/icons/icons'; import { Cancel } from '../../common/icons/icons';
import { compareExpenseItems, getExpenseItemLabel } from '../utils/expenseItemOptions';
const SelectExpenseItemModalComponent = ({ isOpen, onClose, onSelect, formId, title = '', isSaving = false, sheet }) => { const SelectExpenseItemModalComponent = ({ isOpen, onClose, onSelect, formId, title = '', isSaving = false, sheet }) => {
const [selectedValue, setSelectedValue] = useState(''); const [selectedValue, setSelectedValue] = useState('');
@ -14,7 +15,7 @@ const SelectExpenseItemModalComponent = ({ isOpen, onClose, onSelect, formId, ti
if (!isOpen || formId == null) return; if (!isOpen || formId == null) return;
ExpenseItemApi.getAll({ r_start: true, sheet: sheet }).then((data) => { ExpenseItemApi.getAll({ r_start: true, sheet: sheet }).then((data) => {
if (data.success) { if (data.success) {
setExpenseItemOption(data.result); setExpenseItemOption([...data.result].sort(compareExpenseItems));
return; return;
} }
toast.error('Ошибка получения статья расходов'); toast.error('Ошибка получения статья расходов');
@ -69,7 +70,7 @@ const SelectExpenseItemModalComponent = ({ isOpen, onClose, onSelect, formId, ti
size='small' size='small'
options={expenseItemOptions} options={expenseItemOptions}
noOptionsText='Не найдено' noOptionsText='Не найдено'
getOptionLabel={(option) => option.name || ''} getOptionLabel={getExpenseItemLabel}
getOptionKey={(option) => option.id} getOptionKey={(option) => option.id}
value={selectedValue} value={selectedValue}
onChange={(_event, newValue) => { onChange={(_event, newValue) => {

View File

@ -0,0 +1,22 @@
const getItemCode = (option) => {
const code = option?.item_id;
if (code == null) return '';
return String(code).trim();
};
export const getExpenseItemLabel = (option) => {
if (!option || typeof option !== 'object') return '';
const code = getItemCode(option);
const name = option.name || '';
if (code && name) return `${code} — ${name}`;
return code || name;
};
export const compareExpenseItems = (a, b) => {
const codeA = getItemCode(a);
const codeB = getItemCode(b);
if (!codeA && !codeB) return 0;
if (!codeA) return 1;
if (!codeB) return -1;
return codeA.localeCompare(codeB, 'ru', { numeric: true });
};

View File

@ -0,0 +1,27 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { compareExpenseItems, getExpenseItemLabel } from './expenseItemOptions.js';
const sorted = (ids) =>
ids
.map((item_id) => ({ item_id, name: 'x' }))
.sort(compareExpenseItems)
.map((o) => o.item_id);
test('AURORA-1989: подпись варианта', () => {
assert.equal(getExpenseItemLabel({ item_id: '3.01.', name: 'Связь' }), '3.01. — Связь');
assert.equal(getExpenseItemLabel({ item_id: null, name: 'Связь' }), 'Связь');
assert.equal(getExpenseItemLabel({ name: '' }), '');
assert.equal(getExpenseItemLabel(''), '');
});
test('AURORA-1989: сортировка с учётом числовых частей, без кода — в конце', () => {
assert.deepEqual(sorted(['3.10.', '3.2.', '10', '2']), ['2', '3.2.', '3.10.', '10']);
assert.deepEqual(sorted([null, '1.', '']), ['1.', null, '']);
});
test('AURORA-1989: поиск по подписи находит номер и название', () => {
const label = getExpenseItemLabel({ item_id: '3.01.', name: 'Связь' });
assert.ok(label.includes('3.01'));
assert.ok(label.includes('Связь'));
});