From 64284a29179c43b29b52d52bd72a15d4f242dd5e Mon Sep 17 00:00:00 2001 From: Veronika Tsygankova Date: Thu, 12 Nov 2026 09:07:20 +0300 Subject: [PATCH] =?UTF-8?q?[AURORA-2006]=20-=20=D0=93=D1=83=D0=B4=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=D0=BB=20(=D0=B2=D0=BA=D0=BB=D0=B0=D0=B4=D0=BA?= =?UTF-8?q?=D0=B0):=20=D0=BC=D0=B5=D0=BB=D0=BA=D0=B8=D0=B5=20=D0=B4=D0=B5?= =?UTF-8?q?=D1=84=D0=B5=D0=BA=D1=82=D1=8B=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5?= =?UTF-8?q?=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ответы 404/409 при «Сохранить» перечитывают таблицу - Исправлено поведение Стрелки раскрытия блока - Вывод сообщения об ошибке - Убран лишние лишний CSS из шахматки - hooks/useFullScreen.tsx => hooks/useFullScreen.ts, убрано удблирование типов --- .../{useFullScreen.tsx => useFullscreen.ts} | 0 web/src/types/goodwill/goodwill.ts | 9 +- .../ConsolidationGoodwillContent.tsx | 206 ++++++++++-------- .../ConsolidationGoodwillTable.css | 10 - .../ConsolidationGoodwillTable.tsx | 6 +- 5 files changed, 126 insertions(+), 105 deletions(-) rename web/src/hooks/{useFullScreen.tsx => useFullscreen.ts} (100%) diff --git a/web/src/hooks/useFullScreen.tsx b/web/src/hooks/useFullscreen.ts similarity index 100% rename from web/src/hooks/useFullScreen.tsx rename to web/src/hooks/useFullscreen.ts diff --git a/web/src/types/goodwill/goodwill.ts b/web/src/types/goodwill/goodwill.ts index 96439be..21f33fc 100644 --- a/web/src/types/goodwill/goodwill.ts +++ b/web/src/types/goodwill/goodwill.ts @@ -1,8 +1,5 @@ /** DTO таблицы гудвилла — по `api/src/schemas/goodwill.py` и `../docs/dev/api-contract-goodwill.md`. Деньги и доля — строки. */ -export interface Ref { - id: string; - name: string; -} +import type { ReadOnlyReason, Ref } from '../corrections'; export interface GoodwillWarning { code: 'CAPITAL_SOURCE_MISSING' | 'CAPITAL_SOURCE_AMBIGUOUS' | 'OWNERSHIP_TOTAL_EXCEEDED' | string; @@ -42,13 +39,11 @@ export interface GoodwillGroup { totals: GoodwillTotals; } -export type GoodwillReadOnlyReason = 'VERSION_NOT_EDITABLE' | 'LOCK_REQUIRED' | 'LOCKED_BY_OTHER'; - export interface GoodwillTableResponse { version_id: string; goodwill_enabled: boolean; editable: boolean; - read_only_reason: GoodwillReadOnlyReason | null; + read_only_reason: ReadOnlyReason | null; rows: GoodwillRow[]; groups: GoodwillGroup[]; totals: GoodwillTotals; diff --git a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillContent/ConsolidationGoodwillContent.tsx b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillContent/ConsolidationGoodwillContent.tsx index 21d0fc3..37e40c1 100644 --- a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillContent/ConsolidationGoodwillContent.tsx +++ b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillContent/ConsolidationGoodwillContent.tsx @@ -1,18 +1,18 @@ import { DownloadOutlined, EditOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons'; -import { Alert, Button, ConfigProvider, Select, Space, Switch, Tooltip, Typography } from 'antd'; +import { Alert, Button, ConfigProvider, Flex, Select, Space, Switch, Tooltip, Typography } from 'antd'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useParams } from 'react-router-dom'; import { ApiError } from '../../../api/client'; import { ConsolidationFormatTableFilter } from '../../../components/ConsolidationFormatTableFilter/ConsolidationFormatTableFilter'; import { type ColumnDef, ColumnSettings, useVisibleColumns } from '../../../components/GenericTable'; -import { useFullscreen } from '../../../hooks/useFullScreen'; +import { useFullscreen } from '../../../hooks/useFullscreen'; import { exportGoodwillTable, fetchGoodwillTable, saveGoodwillRows, saveGoodwillSettings } from '../../../services/api/goodwill'; import type { VersionCard } from '../../../types/consolidations/version_members'; import type { GoodwillEdit, GoodwillSign, GoodwillTableResponse } from '../../../types/goodwill/goodwill'; import { saveBlob, xlsxFilename } from '../../../utils/download'; import { changedRows, effectiveRow, matchesSign, parseShare, rowKey } from '../../../utils/goodwill'; import { useNotificationApi } from '../../../utils/useNotification'; -import { readOnlyHint } from '../../CorrectionTable/readOnly'; +import { errorOutcome, readOnlyHint } from '../../CorrectionTable/readOnly'; import { ConsolidationGoodwillTable } from '../ConsolidationGoodwillTable/ConsolidationGoodwillTable'; import { type GoodwillTreeRow, type RowIssues, formatMoney, getGoodwillColumns } from '../ConsolidationGoodwillTable/config'; @@ -45,6 +45,7 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => { const [data, setData] = useState(null); const [loading, setLoading] = useState(false); + const [loadError, setLoadError] = useState(null); const [saving, setSaving] = useState(false); const [settingsSaving, setSettingsSaving] = useState(false); const [decimals, setDecimals] = useState(2); @@ -60,10 +61,14 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => { const loadData = useCallback( async (vId: string) => { setLoading(true); + setLoadError(null); try { setData(await fetchGoodwillTable(vId)); } catch (e) { - if (e instanceof ApiError) notification.error({ description: e.message }); + const message = e instanceof ApiError ? e.message : 'Не удалось загрузить таблицу гудвилла'; + setData(null); + setLoadError(message); + notification.error({ description: message }); } finally { setLoading(false); } @@ -158,6 +163,16 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => { setIsEditMode(false); }; + // сервер закрыл правки (перечитали после 409, версию забрали или закрыли) — выходим из редактирования: + // иначе экран остаётся редактируемым и каждое «Сохранить» снова получает 409 + useEffect(() => { + if (data && !data.editable) { + setEdits({}); + setServerIssues({}); + setIsEditMode(false); + } + }, [data]); + const handleSave = async () => { if (!version_id || !data) return; if (pending.length === 0) { @@ -170,13 +185,21 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => { closeEditing(); notification.success({ description: 'Изменения сохранены' }); } catch (e) { + // 409 (версию закрыли, блокировку забрали) и 404 (пары уже нет) — перечитываем + // таблицу, строку не подсвечиваем; правки в несуществующих парах при пересчёте cбрасываем + const out = errorOutcome(e, 'Не удалось сохранить изменения'); + notification.error({ description: out.message }); + if (out.reload) { + setServerIssues({}); + loadData(version_id); + return; + } const detail = rowErrorDetail(e); if (detail) { const key = `${detail.head_legal_entity_id}:${detail.subsidiary_legal_entity_id}`; const field = ERROR_FIELD[detail.code ?? ''] ?? 'ownership_share'; setServerIssues((prev) => ({ ...prev, [key]: { ...prev[key], [field]: detail.message } })); } - if (e instanceof ApiError) notification.error({ description: e.message }); } finally { setSaving(false); } @@ -188,7 +211,9 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => { try { setData(await saveGoodwillSettings(version_id, { goodwill_enabled: enabled })); } catch (e) { - if (e instanceof ApiError) notification.error({ description: e.message }); + const out = errorOutcome(e, 'Не удалось изменить настройку гудвилла'); + notification.error({ description: out.message }); + if (out.reload) loadData(version_id); } finally { setSettingsSaving(false); } @@ -229,91 +254,98 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => { /> )} -
- -
- - - Гудвилл - + + {sign !== 'all' ? : null} - - {data?.goodwill_enabled - ? `В КФО: ${formatMoney(data.totals.goodwill_in_kfo_amount, units, decimals)}` - : 'Гудвилл не учитывается в КФО'} - - -
-
- - - + + - - - + +
- - } - /> - + } + /> + + )} ); diff --git a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.css b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.css index 322ce45..1da9d38 100644 --- a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.css +++ b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.css @@ -1,18 +1,8 @@ -.goodwillTable .empty-cell { - background-color: #f2f4f7; -} -.goodwillTable .ant-table-tbody > tr:hover > td.empty-cell { - background-color: #f2f4f7 !important; -} - .goodwillTable .ant-table-summary { border-end-end-radius: 8px !important; border-end-start-radius: 8px !important; } -.goodwillTable .ant-table-cell-fix { - background-color: #f8fafc !important; -} .goodwillTable .resRow { background-color: #e6f4ea !important ; } diff --git a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.tsx b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.tsx index 4ac6abf..cad7c23 100644 --- a/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.tsx +++ b/web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable/ConsolidationGoodwillTable.tsx @@ -57,6 +57,10 @@ export const ConsolidationGoodwillTable: React.FC = isFullscreen = false, }) => { const treeData = useMemo(() => buildTree(data, rows), [data, rows]); + const expandIconColumnIndex = Math.max( + 0, + columns.findIndex((col) => col.key === 'name'), + ); return ( @@ -72,7 +76,7 @@ export const ConsolidationGoodwillTable: React.FC = bordered title={() => toolbar} key={treeData.map((g) => g.key).join('|')} - expandable={{ defaultExpandAllRows: true, expandIconColumnIndex: 1 }} + expandable={{ defaultExpandAllRows: true, expandIconColumnIndex }} summary={() => } rowClassName={rowClassName} />