diff --git a/web/src/widgets/NewConsoleModal/CompanyOptionRow.tsx b/web/src/widgets/NewConsoleModal/CompanyOptionRow.tsx
new file mode 100644
index 0000000..ab95355
--- /dev/null
+++ b/web/src/widgets/NewConsoleModal/CompanyOptionRow.tsx
@@ -0,0 +1,120 @@
+import { memo, useCallback, useMemo, useState } from 'react';
+import { LegalEntityBrief } from '../../types/api';
+import { Checkbox, Empty, Input, Spin } from 'antd';
+
+type RowProps = {
+ entity: LegalEntityBrief;
+ checked: boolean;
+ onToggle: (id: string) => void;
+};
+const CompanyOptionRow = memo(({ entity, checked, onToggle }: RowProps) => (
+
onToggle(entity.id)}
+ onKeyDown={(e) => {
+ if (e.key === ' ' || e.key === 'Enter') {
+ e.preventDefault();
+ onToggle(entity.id);
+ }
+ }}
+ style={{
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ width: '100%',
+ minWidth: 0,
+ gap: 12,
+ padding: '10px 8px',
+ borderRadius: 4,
+ borderBottom: '1px solid rgba(0, 0, 0, 0.05)',
+ cursor: 'pointer',
+ boxSizing: 'border-box',
+ }}>
+
+
+ {entity.name}
+
+
+ {entity.inn}
+
+));
+
+type CompanyMultiSelectProps = {
+ companies: LegalEntityBrief[];
+ loading?: boolean;
+ // injected by Form.Item:
+ value?: string[];
+ onChange?: (value: string[]) => void;
+};
+
+export const CompanyMultiSelect: React.FC = ({ companies, loading, value = [], onChange }) => {
+ const [search, setSearch] = useState('');
+
+ const toggle = useCallback(
+ (id: string) => {
+ const next = value.includes(id) ? value.filter((v) => v !== id) : [...value, id];
+ onChange?.(next);
+ },
+ [value, onChange],
+ );
+
+ const filtered = useMemo(() => {
+ if (!search) return companies;
+ const q = search.toLowerCase();
+ return companies.filter((s) => s.name.toLowerCase().includes(q));
+ }, [companies, search]);
+
+ return (
+
+
setSearch(e.target.value)}
+ style={{ marginBottom: 12 }}
+ />
+
+ {loading ? (
+
+
+
+ ) : null}
+ {!loading && filtered.length === 0 ? (
+
+ ) : (
+
+ {filtered.map((s) => (
+
+ ))}
+
+ )}
+
+ {!loading && companies.length > 0 && (
+
+
+ Выбрано: {value.length} / {companies.length}
+
+
+ )}
+
+ );
+};
diff --git a/web/src/widgets/NewConsoleModal/NewConsoleModal.tsx b/web/src/widgets/NewConsoleModal/NewConsoleModal.tsx
index 843001a..e11c0b7 100644
--- a/web/src/widgets/NewConsoleModal/NewConsoleModal.tsx
+++ b/web/src/widgets/NewConsoleModal/NewConsoleModal.tsx
@@ -1,4 +1,4 @@
-import { Checkbox, Col, Empty, Form, Input, Modal, Row, Select, Spin, message } from 'antd';
+import { Col, Form, Modal, Row, Select, message } from 'antd';
import type React from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { ApiError } from '../../api/client';
@@ -7,6 +7,8 @@ import { getCompanyGroupsThunk } from '../../store/slices/companyGroupsSlice/thu
import { useAppDispatch, useAppSelector } from '../../store/store';
import type { ConsolidationCreate, LegalEntityBrief, Quarter, RelatedGroupOut } from '../../types/api';
import { membersFirst, preselectMembers } from './preselect';
+import { PlusOutlined } from '@ant-design/icons';
+import { CompanyMultiSelect } from './CompanyOptionRow';
type Props = {
open: boolean;
@@ -30,13 +32,11 @@ export const NewConsolidationModal: React.FC = ({ open, onCancel, onOk })
const relatedReqRef = useRef(0);
const [submitting, setSubmitting] = useState(false);
- const [legEntSearch, setLegEntSearch] = useState('');
-
const company_group_id = Form.useWatch('company_group_id', form);
const related_group_id = Form.useWatch('related_group_id', form);
const year = Form.useWatch('year', form);
const semester = Form.useWatch('quarter', form);
- const legEntIds = Form.useWatch('legal_entity_ids', form);
+ const legEntIds = Form.useWatch('legal_entity_ids', form) ?? [];
const quarterOptions: { value: Quarter; label: string }[] = [
{ value: 'Q1', label: '1 квартал' },
@@ -64,7 +64,6 @@ export const NewConsolidationModal: React.FC = ({ open, onCancel, onOk })
relatedReqRef.current++; // сменили ГК: ответ по старой ГСК больше не нужен
setLegEntities([]);
setLoadingEntities(false);
- setLegEntSearch('');
legEntReqRef.current++;
};
@@ -114,7 +113,6 @@ export const NewConsolidationModal: React.FC = ({ open, onCancel, onOk })
setLoadingSubgroups(false);
subgroupReqRef.current++;
clearLegEnts();
- setLegEntSearch('');
};
const handleOk = async () => {
@@ -142,25 +140,19 @@ export const NewConsolidationModal: React.FC = ({ open, onCancel, onOk })
onCancel();
};
- const filteredLegEnts = useMemo(() => {
- if (!legEntSearch) return legEntities;
- const q = legEntSearch.toLowerCase();
- return legEntities.filter((s) => s.name.toLowerCase().includes(q));
- }, [legEntities, legEntSearch]);
-
return (
}}
okText='Создать'
cancelText='Отмена'
confirmLoading={submitting}
destroyOnHidden
width={640}>
-