Коммит 7891430 откатил синхронизацию фронта (5bec434, #139/#140) и форматирование Prettier (#137). Из origin/main восстановлены файлы, не относящиеся к шахматке: - index.tsx (тема antd: Layout.fontSize, Form.labelFontSize/labelColor); - layouts/DocumentPage.tsx (переключатель документа, комментарий к документу); - services/api: consolidations.ts (getChecklist), documents.ts (postComment), files.ts (removeFile), directories/catalogue_jur.ts; types/consolidations/version_members.ts (ChecklistBackendShape); - widgets: ConsoleLegalEntities (ChecklistModal, checklist_utils), FilesDrawer (DeleteModal, ReplaceDocModal, documentRows), DocumentReview (CommentModal, StatementReview, reviewCounters, reviewView), CatalogueJurForm, CatalogueJurTable, CompanyGroupsList; - hooks/useVirtualList.tsx и components/TableTag/presets.tsx (форматирование Prettier). В файлах шахматки оставлены её изменения: App.tsx, layouts/index.ts, api/client.ts (init в apiFetchBlob), OsvTabs.tsx, ConsolidatedOsvContent.tsx. Из main возвращён key={version_id}: страница отчёта разделена на обёртку с key и содержимое, чтобы при смене версии состояние (карточка, фильтры, страница) создавалось заново, как в ConsolidatedOsvPage. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
144 lines
5.2 KiB
TypeScript
144 lines
5.2 KiB
TypeScript
import { DownloadOutlined } from '@ant-design/icons';
|
||
import { Button, Space, message } from 'antd';
|
||
import { useEffect, useMemo, useState } from 'react';
|
||
import { ApiError } from '../../api/client';
|
||
import { ColumnSettings, DataTable, useFilteredRows, useVisibleColumns } from '../../components/GenericTable';
|
||
import { useTableFilters } from '../../components/GenericTable/useTableFilters';
|
||
import { downloadChecklistCsv } from '../../services/api/consolidations';
|
||
import { getVersionCard } from '../../services/api/consolidations';
|
||
import { setSelectedLegalEntity, setSelectedVersion } from '../../store/slices/consolidations/consolidationsSlice';
|
||
import { useAppDispatch, useAppSelector } from '../../store/store';
|
||
import type { IVersionCard, MemberRow } from '../../types/consolidations/version_members';
|
||
import { saveBlob } from '../../utils/download';
|
||
import ChecklistModal from './ChecklistModal';
|
||
import { membersConfig } from './config';
|
||
import { normalizeData } from './normalize';
|
||
import { checklistFilename, responsibleName } from './panelInfo';
|
||
|
||
export function ConsoleLegalEntitiesTable({ onDrawerOpen, reloadKey }: { onDrawerOpen: () => void; reloadKey: number }) {
|
||
const dispatch = useAppDispatch();
|
||
const [loading, setLoading] = useState(false);
|
||
const consolidation_id = useAppSelector((s) => s.consolidations.current_version_id);
|
||
const [checklistOpen, setChecklistOpen] = useState(false);
|
||
|
||
const [consolidationData, setConsolidationData] = useState<IVersionCard | null>(null);
|
||
|
||
useEffect(() => {
|
||
async function getLegalEntities() {
|
||
if (!consolidation_id) return;
|
||
setLoading(true);
|
||
try {
|
||
setConsolidationData(await getVersionCard(consolidation_id));
|
||
} catch (e: unknown) {
|
||
message.error(e instanceof ApiError ? e.message : 'Не удалось загрузить карточку версии');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
getLegalEntities();
|
||
}, [consolidation_id, reloadKey]);
|
||
const rawRows = useMemo(() => normalizeData(consolidationData), [consolidationData]);
|
||
|
||
const downloadChecklist = async () => {
|
||
if (!consolidationData) return;
|
||
try {
|
||
const { blob, filename } = await downloadChecklistCsv(consolidationData.id);
|
||
const card = consolidationData;
|
||
saveBlob(blob, filename ?? checklistFilename(card.company_group.name, card.year, card.quarter));
|
||
} catch (e: unknown) {
|
||
message.error(e instanceof ApiError ? e.message : 'Не удалось скачать чек-лист');
|
||
}
|
||
};
|
||
const viewChecklist = () => {
|
||
if (!consolidationData) return;
|
||
setChecklistOpen(true);
|
||
};
|
||
const { visibleKeys, setVisibleKeys } = useVisibleColumns(membersConfig);
|
||
const { rawQuery, columnFilters, setColumnFilters, sort, setSort, resetAll, hasActiveFilters } = useTableFilters<MemberRow>();
|
||
// single filtered array — title count and table share it
|
||
const { rows: filtered } = useFilteredRows(rawRows, membersConfig, rawQuery, columnFilters, sort);
|
||
const onRow = (row: MemberRow) => ({
|
||
onClick: () => {
|
||
dispatch(setSelectedVersion(row.version_id));
|
||
dispatch(setSelectedLegalEntity(row.id));
|
||
onDrawerOpen();
|
||
},
|
||
});
|
||
|
||
return (
|
||
<>
|
||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||
<Space
|
||
style={{
|
||
width: '100%',
|
||
justifyContent: 'space-between',
|
||
padding: '12px 16px',
|
||
flex: 0,
|
||
}}>
|
||
<div style={{ display: 'flex', alignItems: 'baseline', gap: 8, margin: 0 }}>
|
||
<h2
|
||
style={{
|
||
display: 'block',
|
||
boxSizing: 'border-box',
|
||
fontSize: 17,
|
||
fontWeight: 600,
|
||
margin: 0,
|
||
}}>
|
||
Организации
|
||
</h2>
|
||
<span style={{ fontSize: 13, color: 'rgb(102, 112, 133)' }}>{rawRows.length} шт.</span>
|
||
{consolidationData && (
|
||
// «Утверждён в РФ» / «Верифицирован в ГО» — маршрут согласования, Срез 7
|
||
<span
|
||
style={{
|
||
fontSize: 13,
|
||
color: 'rgb(102, 112, 133)',
|
||
marginLeft: 8,
|
||
}}>
|
||
Ответственный: {responsibleName(consolidationData)} Утверждён в РФ: — Верифицирован в ГО: —
|
||
</span>
|
||
)}
|
||
</div>
|
||
<div>
|
||
{hasActiveFilters && (
|
||
<Button
|
||
type='default'
|
||
onClick={() => {
|
||
resetAll();
|
||
}}>
|
||
Сбросить фильтры
|
||
</Button>
|
||
)}
|
||
<ColumnSettings defs={membersConfig.columns} visibleKeys={visibleKeys} onChange={setVisibleKeys} />
|
||
<Button icon={<DownloadOutlined />} disabled={!consolidationData} onClick={viewChecklist} style={{ marginLeft: 8 }}>
|
||
Скачать чек-лист
|
||
</Button>
|
||
</div>
|
||
</Space>
|
||
<DataTable
|
||
config={membersConfig}
|
||
rows={filtered}
|
||
allRows={rawRows}
|
||
loading={loading}
|
||
visibleKeys={visibleKeys}
|
||
columnFilters={columnFilters}
|
||
onColumnFiltersChange={setColumnFilters}
|
||
sortState={sort}
|
||
onSortChange={setSort}
|
||
onRow={onRow}
|
||
/>
|
||
</div>
|
||
{consolidationData && (
|
||
<ChecklistModal
|
||
open={checklistOpen}
|
||
onClose={() => {
|
||
setChecklistOpen(false);
|
||
}}
|
||
onDownload={downloadChecklist}
|
||
consolidationData={consolidationData}
|
||
/>
|
||
)}
|
||
</>
|
||
);
|
||
}
|