fix(web): список консолидаций и «Взять в работу» по спеке (AURORA-1589, PR #166)
«Только в работе» выключен по умолчанию, параметр — boolean; ошибка загрузки списка показывается; пункты «⋯» disabled с подсказкой «Будет позже», клик не выбирает строку; «Взять в работу» неактивна по коду CANCELLED. Модалка [35]: опечатки, плейсхолдер, ≤ 1000 символов, «К3», ошибки (403 и прочие) — текст сервера, ФИО без второй точки; после взятия в работу перечитываются список и панель «Организации» («Ответственный»). Боковое меню: thunk списка с объектом, отступ секций. Порядок импортов (biome). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ccca6dfa13
commit
d71c46e846
@ -1,6 +1,6 @@
|
||||
import { Settings2 } from 'lucide-react';
|
||||
import { Button, Checkbox, Dropdown } from 'antd';
|
||||
import type { MenuProps } from 'antd';
|
||||
import { Settings2 } from 'lucide-react';
|
||||
import { type ColumnDef, isGroup } from './tableTypes';
|
||||
|
||||
interface Props<T> {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Filter } from 'lucide-react';
|
||||
import { Table } from 'antd';
|
||||
import type { TableProps } from 'antd';
|
||||
import type { ColumnGroupType, ColumnType, ColumnsType } from 'antd/es/table';
|
||||
import { Filter } from 'lucide-react';
|
||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
import { CustomFilterDropdown } from './CustomFilterDropdown';
|
||||
import { Highlight } from './Highlight';
|
||||
|
||||
@ -5,16 +5,14 @@ import { ApiError } from '../api/client';
|
||||
import PageTitle from '../components/PageTitle';
|
||||
import { fetchOneCompanyGroup } from '../services/api/directories/company_groups';
|
||||
import { setSelectedVersion } from '../store/slices/consolidations/consolidationsSlice';
|
||||
import { getConsolidationsListThunk } from '../store/slices/consolidations/thunks';
|
||||
import { useAppDispatch } from '../store/store';
|
||||
import { ConsoleLegalEntitiesTable } from '../widgets/ConsoleLegalEntities/ConsoleLegalEntities';
|
||||
import { ConsoleTableWidget } from '../widgets/ConsoleTable/ConsoleTable';
|
||||
import { DocumentsDrawer } from '../widgets/FilesDrawer/FilesDrawer';
|
||||
|
||||
// unwrap() бросает rejectValue (строку), fetch группы — ApiError
|
||||
// список консолидаций грузит ConsoleTableWidget (с фильтром «Только в работе»), здесь — только группа
|
||||
function errorText(e: unknown): string {
|
||||
if (e instanceof ApiError) return e.message;
|
||||
if (typeof e === 'string') return e;
|
||||
return 'Не удалось загрузить группу компаний';
|
||||
}
|
||||
|
||||
@ -43,7 +41,7 @@ export function ConsolidationPage() {
|
||||
}
|
||||
}
|
||||
getAllInfo(group_id);
|
||||
}, [dispatch, group_id]);
|
||||
}, [group_id]);
|
||||
|
||||
// выбор версии следует за ?version= и не перезагружает список
|
||||
useEffect(() => {
|
||||
@ -85,7 +83,8 @@ export function ConsolidationPage() {
|
||||
flexDirection: 'column',
|
||||
minHeight: 0,
|
||||
}}>
|
||||
<ConsoleTableWidget />
|
||||
{/* после «Взять в работу» перечитываем и панель «Организации»: в ней «Ответственный» */}
|
||||
<ConsoleTableWidget onVersionLocked={() => setReloadKey((k) => k + 1)} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
|
||||
@ -1,85 +1,63 @@
|
||||
import { DownOutlined, RightOutlined } from '@ant-design/icons';
|
||||
import { Button, Checkbox, Dropdown, Space, Tooltip, message } from 'antd';
|
||||
import { Button, Checkbox, Dropdown, type MenuProps, Space, Tooltip, message } from 'antd';
|
||||
import type { ColumnsType, TableProps } from 'antd/es/table';
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { ArrowRight, Briefcase, GitBranchPlus, History, MoreHorizontal, ToggleLeft } from 'lucide-react';
|
||||
import { type ReactNode, memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { useCurrentUser } from '../../auth/MeContext';
|
||||
import { ColumnSettings, DataTable, type TableConfig, isGroup, useFilteredRows, useVisibleColumns } from '../../components/GenericTable';
|
||||
import { useTableFilters } from '../../components/GenericTable/useTableFilters';
|
||||
import { getConsolidationsListThunk } from '../../store/slices/consolidations/thunks';
|
||||
import { useAppDispatch, useAppSelector } from '../../store/store';
|
||||
import type { ConsRow } from '../../types/consolidations/consolidations';
|
||||
import { canTakeInWork, isLockedBy, parseInWorkOnly } from '../../utils/consolidations';
|
||||
import LockModal from './LockModal';
|
||||
import { consConfigBase } from './config';
|
||||
import { flattenCons } from './flatten';
|
||||
import { groupAdjacent } from './groupAdjacent';
|
||||
import { useGrouping } from './useGrouping';
|
||||
import { ArrowRight, Briefcase, GitBranchPlus, History, MoreHorizontal, ToggleLeft } from 'lucide-react';
|
||||
import { useCurrentUser } from '../../auth/MeContext';
|
||||
import LockModal from './LockModal';
|
||||
import { LockOut } from '../../types/consolidations/common_types';
|
||||
import { Me } from '../../api/types';
|
||||
import { getConsolidationsListThunk } from '../../store/slices/consolidations/thunks';
|
||||
|
||||
type ActionKey = 'copy' | 'disable_confirm' | 'history';
|
||||
const ITEMS = [
|
||||
{
|
||||
key: 'copy',
|
||||
label: (
|
||||
<Tooltip title='Будет позже'>
|
||||
<span style={{ display: 'block', width: '100%', cursor: 'not-allowed' }}>Добавить версию</span>
|
||||
</Tooltip>
|
||||
),
|
||||
className: 'ant-dropdown-menu-item-disabled',
|
||||
icon: <GitBranchPlus size={14} />,
|
||||
},
|
||||
{
|
||||
key: 'disable_confirm',
|
||||
label: (
|
||||
<Tooltip title='Будет позже'>
|
||||
<span style={{ display: 'block', width: '100%', cursor: 'not-allowed' }}>Отключить подтверждение КФО</span>
|
||||
</Tooltip>
|
||||
),
|
||||
className: 'ant-dropdown-menu-item-disabled',
|
||||
icon: <ToggleLeft size={14} />,
|
||||
},
|
||||
{
|
||||
key: 'history',
|
||||
label: (
|
||||
<Tooltip title='Будет позже'>
|
||||
<span style={{ display: 'block', width: '100%', cursor: 'not-allowed' }}>История изменений</span>
|
||||
</Tooltip>
|
||||
),
|
||||
className: 'ant-dropdown-menu-item-disabled',
|
||||
icon: <History size={14} />,
|
||||
},
|
||||
{},
|
||||
] as const;
|
||||
const SOON = 'Будет позже';
|
||||
|
||||
const RowActions = memo(function RowActions({ row, onAction }: { row: ConsRow; onAction: (key: ActionKey, _row: ConsRow) => void }) {
|
||||
// пункт неактивен (disabled — клик не обрабатывается), подсказка — на подписи
|
||||
const soonItem = (key: string, label: string, icon: ReactNode) => ({
|
||||
key,
|
||||
disabled: true,
|
||||
icon,
|
||||
label: (
|
||||
<Tooltip title={SOON}>
|
||||
<span style={{ display: 'block', width: '100%' }}>{label}</span>
|
||||
</Tooltip>
|
||||
),
|
||||
});
|
||||
|
||||
// функций ещё нет: «История изменений» — после журнала с фильтрами [43-02], остальное — зонтичная задача экранов консолидаций
|
||||
const ITEMS: MenuProps['items'] = [
|
||||
soonItem('copy', 'Добавить версию', <GitBranchPlus size={14} />),
|
||||
soonItem('disable_confirm', 'Отключить подтверждение КФО', <ToggleLeft size={14} />),
|
||||
soonItem('history', 'История изменений', <History size={14} />),
|
||||
];
|
||||
|
||||
const RowActions = memo(function RowActions() {
|
||||
return (
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
menu={{
|
||||
items: ITEMS as any,
|
||||
onClick: ({ key, domEvent }) => {
|
||||
domEvent.stopPropagation();
|
||||
onAction(key as ActionKey, row);
|
||||
},
|
||||
}}>
|
||||
<Button icon={<MoreHorizontal size={14} />} onClick={(e) => e.stopPropagation()} />
|
||||
</Dropdown>
|
||||
// меню рендерится в портал, но React-событие всплывает по дереву до onRow строки — гасим здесь
|
||||
<span onClick={(e) => e.stopPropagation()} onKeyDown={(e) => e.stopPropagation()}>
|
||||
<Dropdown trigger={['click']} menu={{ items: ITEMS }}>
|
||||
<Button icon={<MoreHorizontal size={14} />} aria-label='Действия' />
|
||||
</Dropdown>
|
||||
</span>
|
||||
);
|
||||
});
|
||||
function isLockedByCurrentUser(currentUser: Me, lockData: LockOut | null) {
|
||||
if (lockData === null) return false;
|
||||
if (lockData.locked_by !== currentUser.id) return false;
|
||||
return true;
|
||||
}
|
||||
export function ConsoleTableWidget() {
|
||||
|
||||
/** `onVersionLocked` — версию взяли в работу: страница перечитывает панель «Организации» («Ответственный»). */
|
||||
export function ConsoleTableWidget({ onVersionLocked }: { onVersionLocked?: () => void }) {
|
||||
const navigate = useNavigate();
|
||||
const { group_id } = useParams();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const consolidations = useAppSelector((s) => s.consolidations.consolidations);
|
||||
const loading = useAppSelector((s) => s.consolidations.loading);
|
||||
const inWorkOnly = searchParams.get('in_work_only') || true;
|
||||
// «Только в работе» по умолчанию выключен (макет [34], умолчание API — false)
|
||||
const inWorkOnly = parseInWorkOnly(searchParams.get('in_work_only'));
|
||||
const currentUser = useCurrentUser();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@ -96,11 +74,12 @@ export function ConsoleTableWidget() {
|
||||
const { visibleRows, expanded, toggle } = useGrouping(grouped);
|
||||
const loadConsolidations = useCallback(async () => {
|
||||
if (!group_id) return;
|
||||
let in_work_only = true;
|
||||
if (inWorkOnly === 'false') {
|
||||
in_work_only = false;
|
||||
try {
|
||||
await dispatch(getConsolidationsListThunk({ company_group_id: group_id, in_work_only: inWorkOnly })).unwrap();
|
||||
} catch (e: unknown) {
|
||||
// unwrap() бросает rejectValue — текст ошибки сервера
|
||||
message.error(typeof e === 'string' ? e : 'Не удалось загрузить консолидации');
|
||||
}
|
||||
await dispatch(getConsolidationsListThunk({ company_group_id: group_id, in_work_only })).unwrap();
|
||||
}, [dispatch, group_id, inWorkOnly]);
|
||||
useEffect(() => {
|
||||
loadConsolidations();
|
||||
@ -152,16 +131,6 @@ export function ConsoleTableWidget() {
|
||||
|
||||
const { visibleKeys, setVisibleKeys } = useVisibleColumns(config);
|
||||
|
||||
const handleDropdownAction = useCallback(
|
||||
(key: ActionKey, _row: ConsRow) => {
|
||||
if (key === 'history') {
|
||||
navigate('/logging');
|
||||
} else {
|
||||
message.info('Будет позже');
|
||||
}
|
||||
},
|
||||
[navigate],
|
||||
);
|
||||
const extraColumns: ColumnsType<ConsRow> = useMemo(
|
||||
() => [
|
||||
{
|
||||
@ -170,7 +139,7 @@ export function ConsoleTableWidget() {
|
||||
width: 120,
|
||||
render: (_: unknown, row: ConsRow) => (
|
||||
<div style={{ display: 'flex', gap: 4 }}>
|
||||
{isLockedByCurrentUser(currentUser, row.lock) ? (
|
||||
{isLockedBy(row.lock, currentUser.id) ? (
|
||||
<Button disabled icon={<Briefcase size={16} />} type='default'>
|
||||
В работе
|
||||
</Button>
|
||||
@ -179,7 +148,7 @@ export function ConsoleTableWidget() {
|
||||
iconPlacement='start'
|
||||
icon={<Briefcase size={16} />}
|
||||
type='default'
|
||||
disabled={row.status === 'Отменён'}
|
||||
disabled={!canTakeInWork(row.status_code)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setLockVersionId(row.id);
|
||||
@ -198,13 +167,17 @@ export function ConsoleTableWidget() {
|
||||
}}>
|
||||
К отчётности
|
||||
</Button>
|
||||
<RowActions row={row} onAction={handleDropdownAction} />
|
||||
<RowActions />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
],
|
||||
[navigate, group_id, handleDropdownAction, currentUser],
|
||||
[navigate, group_id, currentUser],
|
||||
);
|
||||
const afterLock = useCallback(() => {
|
||||
loadConsolidations();
|
||||
onVersionLocked?.();
|
||||
}, [loadConsolidations, onVersionLocked]);
|
||||
|
||||
const onRow: TableProps<ConsRow>['onRow'] = (row) => ({
|
||||
// выбранная версия живёт в URL (?version=): переживает уход на «К отчётности» и «Назад»
|
||||
@ -252,7 +225,7 @@ export function ConsoleTableWidget() {
|
||||
</Button>
|
||||
)}
|
||||
<Checkbox
|
||||
checked={searchParams.get('in_work_only') === 'false' ? false : true}
|
||||
checked={inWorkOnly}
|
||||
onChange={(e) => {
|
||||
setSearchParams(
|
||||
(searchParams) => {
|
||||
@ -284,7 +257,7 @@ export function ConsoleTableWidget() {
|
||||
open={lockModalOpen}
|
||||
versionId={lockVersionId}
|
||||
onOpenChange={setLockModalOpen}
|
||||
handleReload={loadConsolidations}
|
||||
handleReload={afterLock}
|
||||
currentUserId={currentUser.id}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
import { Alert, Button, Input, Modal, Skeleton, message } from 'antd';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { LockOut } from '../../types/consolidations/common_types';
|
||||
import { Alert, Button, Input, message, Modal, Skeleton } from 'antd';
|
||||
import { ApiError } from '../../api/client';
|
||||
import { useBeforeUnload } from '../../hooks/useBeforeUnload';
|
||||
import { getVersionCard, lockVersion } from '../../services/api/consolidations';
|
||||
import type { LockOut } from '../../types/consolidations/common_types';
|
||||
import { MAX_REASON_LENGTH, endSentence, isValidReason } from '../../utils/consolidations';
|
||||
import { quarterShortLabel } from '../../utils/labels';
|
||||
|
||||
type LockModalProps = {
|
||||
versionId: string | null;
|
||||
@ -11,12 +14,8 @@ type LockModalProps = {
|
||||
currentUserId: string;
|
||||
handleReload: () => void;
|
||||
};
|
||||
function isValidReason(reason: string) {
|
||||
const trimmed = reason.trim();
|
||||
if (trimmed.length > 0 && trimmed.length < 1000) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** «Взять консолидацию в работу?» [35]: свободная версия — подтверждение, чужая — перехват с причиной. */
|
||||
export default function LockModal({ versionId, open, onOpenChange, currentUserId, handleReload }: LockModalProps) {
|
||||
const [data, setData] = useState<LockOut | null>(null);
|
||||
const [consolidationName, setConsolidationName] = useState<string | null>(null);
|
||||
@ -27,11 +26,14 @@ export default function LockModal({ versionId, open, onOpenChange, currentUserId
|
||||
const [conflict, setConflict] = useState(false);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
// Stale-response guard for fast open/switch/close sequences.
|
||||
// Защита от устаревшего ответа при быстром открытии/смене версии/закрытии.
|
||||
const reqId = useRef(0);
|
||||
|
||||
const close = useCallback(() => onOpenChange(false), [onOpenChange]);
|
||||
|
||||
// введённая причина перехвата — несохранённая правка: браузер предупредит при закрытии вкладки
|
||||
useBeforeUnload(open && reason.trim() !== '');
|
||||
|
||||
const load = useCallback(async () => {
|
||||
if (!versionId) return;
|
||||
const my = ++reqId.current;
|
||||
@ -39,16 +41,14 @@ export default function LockModal({ versionId, open, onOpenChange, currentUserId
|
||||
setLoadError(false);
|
||||
try {
|
||||
const currentCard = await getVersionCard(versionId);
|
||||
const lockData = currentCard.lock;
|
||||
const { company_group, year, quarter } = currentCard;
|
||||
const consName = `${year} ${quarter} · ${company_group.name}`;
|
||||
if (my !== reqId.current) return; // a newer request won
|
||||
setData(lockData);
|
||||
setConsolidationName(consName);
|
||||
if (my !== reqId.current) return; // успел прийти ответ на более новый запрос
|
||||
setData(currentCard.lock);
|
||||
setConsolidationName(`${year} ${quarterShortLabel(quarter)} · ${company_group.name}`);
|
||||
} catch (e) {
|
||||
if (my !== reqId.current) return;
|
||||
if (e instanceof ApiError && e.status === 404) {
|
||||
message.warning('Версия консолидации не обнаржуена');
|
||||
message.warning('Версия консолидации не обнаружена');
|
||||
close();
|
||||
return;
|
||||
}
|
||||
@ -58,46 +58,47 @@ export default function LockModal({ versionId, open, onOpenChange, currentUserId
|
||||
}
|
||||
}, [versionId, close]);
|
||||
|
||||
// Reset + fetch on every open, and on target change while open.
|
||||
// Сброс и загрузка при каждом открытии и при смене версии в открытой модалке (load меняется вместе с versionId).
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
const requests = reqId; // счётчик запросов, а не DOM-узел: в cleanup нужен его актуальный .current
|
||||
setReason('');
|
||||
setConflict(false);
|
||||
setData(null);
|
||||
setLoadError(false);
|
||||
load();
|
||||
return () => {
|
||||
reqId.current++; // invalidate in-flight response on close/switch
|
||||
requests.current++; // ответ в полёте больше не нужен
|
||||
};
|
||||
}, [open, versionId, load]);
|
||||
}, [open, load]);
|
||||
|
||||
const hasToReason = !loading && data !== null && data.locked_by !== currentUserId;
|
||||
|
||||
const handleOk = async () => {
|
||||
if (!versionId || loading || submitting) return;
|
||||
if (hasToReason && !reason.trim()) return;
|
||||
if (hasToReason && !isValidReason(reason)) return;
|
||||
setSubmitting(true);
|
||||
try {
|
||||
const result = await lockVersion(versionId, hasToReason ? reason.trim() : null);
|
||||
|
||||
await lockVersion(versionId, hasToReason ? reason.trim() : null);
|
||||
close();
|
||||
message.success('Консолидация взята в работу.');
|
||||
handleReload();
|
||||
} catch (e) {
|
||||
if (e instanceof ApiError && e.status === 409) {
|
||||
if (e.code === 'VERSION_NOT_EDITABLE') {
|
||||
message.error('Нельзя взять в работу отменённую версию.');
|
||||
close();
|
||||
} else if (e.code === 'LOCKED_BY_OTHER' && !conflict) {
|
||||
await load();
|
||||
setConflict(true);
|
||||
setReason('');
|
||||
}
|
||||
if (e instanceof ApiError && e.code === 'VERSION_NOT_EDITABLE') {
|
||||
message.error('Нельзя взять в работу отменённую версию.');
|
||||
close();
|
||||
handleReload();
|
||||
} else if (e instanceof ApiError && e.code === 'LOCKED_BY_OTHER' && !conflict) {
|
||||
// версию взяли, пока модалка была открыта, — режим перехвата
|
||||
await load();
|
||||
setConflict(true);
|
||||
setReason('');
|
||||
} else {
|
||||
message.error('Что-то пошло не так. Попробуйте снова.');
|
||||
// 403 без права, прочие 409/422 — текст сервера
|
||||
message.error(e instanceof ApiError ? e.message : 'Не удалось взять консолидацию в работу');
|
||||
}
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
handleReload();
|
||||
}
|
||||
};
|
||||
|
||||
@ -110,6 +111,7 @@ export default function LockModal({ versionId, open, onOpenChange, currentUserId
|
||||
closable={!submitting}
|
||||
okText='Взять в работу'
|
||||
okButtonProps={{ disabled: loading || loadError || (hasToReason && !isValidReason(reason)) }}
|
||||
confirmLoading={submitting}
|
||||
cancelText='Отмена'
|
||||
onOk={handleOk}
|
||||
cancelButtonProps={{ disabled: submitting }}>
|
||||
@ -119,10 +121,10 @@ export default function LockModal({ versionId, open, onOpenChange, currentUserId
|
||||
<Alert
|
||||
type='error'
|
||||
showIcon
|
||||
title='Не получилось загрузить нформацию о текущей блокировке'
|
||||
title='Не удалось загрузить информацию о текущей блокировке'
|
||||
action={
|
||||
<Button size='small' onClick={load}>
|
||||
Попробовать перезагрузить
|
||||
Повторить
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
@ -141,12 +143,13 @@ export default function LockModal({ versionId, open, onOpenChange, currentUserId
|
||||
|
||||
{hasToReason && data ? (
|
||||
<>
|
||||
<p style={{ marginTop: 0 }}>Консолидация взята в работу {data.locked_by_name}. Укажите причину замены.</p>
|
||||
<p style={{ marginTop: 0 }}>Консолидация взята в работу {endSentence(data.locked_by_name)} Укажите причину замены.</p>
|
||||
<Input.TextArea
|
||||
autoFocus
|
||||
placeholder='Type message'
|
||||
placeholder='Укажите причину замены'
|
||||
value={reason}
|
||||
maxLength={1000}
|
||||
maxLength={MAX_REASON_LENGTH}
|
||||
showCount
|
||||
rows={3}
|
||||
onChange={(e) => setReason(e.target.value)}
|
||||
/>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { LeftOutlined, PlusOutlined, RightOutlined } from '@ant-design/icons';
|
||||
import { Button, Divider, Layout, Tooltip, message } from 'antd';
|
||||
import { Archive, Building2, ScrollText, UserCog2, Users2 } from 'lucide-react';
|
||||
import { type ReactNode, memo, useState } from 'react';
|
||||
import { NavLink, useNavigate } from 'react-router-dom';
|
||||
import { USERS_ADMIN } from '../../auth/permissions';
|
||||
@ -10,7 +11,6 @@ import { useAppDispatch } from '../../store/store';
|
||||
import { quarterLabel } from '../../utils/labels';
|
||||
import { NewConsolidationModal } from '../NewConsoleModal/NewConsoleModal';
|
||||
import styles from './styles.module.css';
|
||||
import { Archive, Building2, ScrollText, UserCog2, Users2 } from 'lucide-react';
|
||||
|
||||
type CollapsedIconProps = {
|
||||
icon: ReactNode;
|
||||
@ -205,7 +205,8 @@ export function Sidebar() {
|
||||
onOk={async (values) => {
|
||||
const card = await createConsolidation(values);
|
||||
// перечитываем список: на странице группы он сам не обновится, и новая консолидация не станет текущей
|
||||
await dispatch(getConsolidationsListThunk(values.company_group_id));
|
||||
// in_work_only: false — переход ниже открывает список без ?in_work_only (флажок выключен)
|
||||
await dispatch(getConsolidationsListThunk({ company_group_id: values.company_group_id, in_work_only: false }));
|
||||
setModalOpen(false);
|
||||
message.success(`Создана консолидация ${values.year}, ${quarterLabel(values.quarter)}`);
|
||||
navigate(`/groups/${values.company_group_id}?version=${card.id}`);
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
|
||||
.section {
|
||||
margin-bottom: 0px;
|
||||
/* padding: 12px; */
|
||||
/* отступ сверху и снизу, как в макете [34]; по горизонтали пункты выровнены по кнопке «Новая консолидация» */
|
||||
padding: 12px 0;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user