added company group table #31

Merged
aep merged 13 commits from feat/legalEntities into test 2026-10-19 10:35:19 +03:00
16 changed files with 308 additions and 195 deletions
Showing only changes of commit 25d2211ae6 - Show all commits

View File

@ -39,4 +39,9 @@ export const TAG_PRESETS = {
borderColor: 'rgba(245, 158, 11, 0.25)',
color: 'rgb(146, 64, 14)',
},
gray: {
color: 'rgb(71, 84, 103)',
bgColor: 'rgb(248, 250, 252)',
borderColor: 'rgba(15, 23, 42, 0.08)',
},
} as const;

View File

@ -0,0 +1,51 @@
import { useCallback, useMemo, useRef, useState } from "react";
type Options = {
/** высота одного элемента в px (фиксированная) */
itemHeight: number;
/** высота контейнера в px (видимая область) */
containerHeight: number;
/** сколько элементов рендерить дополнительно сверху/снизу */
overscan?: number;
};
export function useVirtualList<T>(items: T[], options: Options) {
const { itemHeight, containerHeight, overscan = 5 } = options;
const [scrollTop, setScrollTop] = useState(0);
const ref = useRef<HTMLDivElement | null>(null);
const totalHeight = items.length * itemHeight;
const startIndex = Math.max(
0,
Math.floor(scrollTop / itemHeight) - overscan,
);
const endIndex = Math.min(
items.length,
Math.ceil((scrollTop + containerHeight) / itemHeight) + overscan,
);
const visibleItems = useMemo(
() => items.slice(startIndex, endIndex).map((item, i) => ({
item,
index: startIndex + i,
})),
[items, startIndex, endIndex],
);
const offsetY = startIndex * itemHeight;
const onScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
setScrollTop(e.currentTarget.scrollTop);
}, []);
return {
ref,
onScroll,
visibleItems,
totalHeight,
offsetY,
};
}

View File

@ -95,15 +95,24 @@ export function CatalogueGroup() {
}
async function getRelatedGroupsHandler() {
setRelatedGroupLoading(true);
if (activeCompanyGroup?.id) {
const res = await fetchRelatedGroups(activeCompanyGroup?.id);
const gsks = res.filter((elem) => elem.kind === 'gsk');
const gszs = res.filter((elem) => elem.kind === 'gsz');
setGskData(gsks);
setGszData(gszs);
setRelatedGroupLoading(true);
try {
const res = await fetchRelatedGroups(activeCompanyGroup?.id);
const gsks = res.filter((elem) => elem.kind === 'gsk');
const gszs = res.filter((elem) => elem.kind === 'gsz');
setGskData(gsks);
setGszData(gszs);
} catch (e) {
if (e instanceof ApiError) {
notification.error({
description: e.message,
});
}
} finally {
setRelatedGroupLoading(false);
}
}
setRelatedGroupLoading(false);
}
useEffect(() => {

View File

@ -7,9 +7,10 @@ import type {
MoveCatalogueJurProps,
WithdrawCatalogueJurProps,
} from '../../../types/catalogueJur/catalogueJur';
import { LE_PAGE } from './company_groups';
export async function fetchCatalogueJur(params: GetCatalogueJurPropsI) {
const res = await api.get<Page<ICatalogueJur>>('/directories/legal-entities', params);
const res = await api.get<Page<ICatalogueJur>>('/directories/legal-entities', {limit:LE_PAGE, offset:0, ...params});
return res;
}

View File

@ -3,7 +3,7 @@ import type { LegalEntityBrief, Page, RelatedGroupDetail, RelatedGroupOut } from
import type { CreateCompanyGroupProps, ICompanyGroupOut } from '../../../types/companyGroups/companyGroups';
const CG_PAGE = 200;
const LE_PAGE = 200;
export const LE_PAGE = 200;
/** Все видимые ГК — дочитываем страницы, пока не получим total. */
export async function fetchCompanyGroups(): Promise<ICompanyGroupOut[]> {

View File

@ -52,13 +52,13 @@ export type WithdrawCatalogueJurProps = {
export type CatalogueJurFormProps = {
inn?: string;
kpp?: string;
kpp?: string | null;
crm_id: string;
entity_type: 'ЮЛ' | 'ИП';
name: string;
aliases?: string[] | { value: string; label: string }[];
company_group_id?: string;
regional_office_id?: string;
gsk_id?: string;
gsz_id?: string;
regional_office_id?: string | null;
gsk_id?: string | null;
gsz_id?: string | null;
};

View File

@ -1,4 +1,4 @@
import { Col, Form, Input, InputNumber, Modal, Row, Select } from 'antd';
import { Col, Form, Input, Modal, Row, Select } from 'antd';
import type React from 'react';
import { useEffect, useMemo, useState } from 'react';
import { ApiError } from '../../api/client';
@ -37,40 +37,62 @@ export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId
async function getInitialData() {
if (jurId) {
setInitialDataLoading(true);
const data = await fetchOneCatalogueJur(jurId);
form.setFieldsValue({
name: data?.name,
aliases: data?.aliases?.map((aliase) => aliase.alias),
crm_id: data?.crm_id,
entity_type: data?.entity_type,
inn: data.inn,
kpp: data?.kpp,
regional_office_id: data?.regional_office_id,
company_group_id: data?.company_group_id,
gsk_id: data.memberships?.find((elem) => elem.kind === 'gsk')?.related_group_id,
gsz_id: data.memberships?.find((elem) => elem.kind === 'gsz')?.related_group_id,
});
setInitialDataLoading(false);
try {
const data = await fetchOneCatalogueJur(jurId);
form.setFieldsValue({
name: data?.name,
aliases: data?.aliases?.map((aliase) => aliase.alias),
crm_id: data?.crm_id,
entity_type: data?.entity_type,
inn: data.inn,
kpp: data?.kpp,
regional_office_id: data?.regional_office_id,
company_group_id: data?.company_group_id,
gsk_id: data.memberships?.find((elem) => elem.kind === 'gsk')?.related_group_id,
gsz_id: data.memberships?.find((elem) => elem.kind === 'gsz')?.related_group_id,
});
} catch (e) {
if (e instanceof ApiError) {
notification.error({ description: e.message });
} else {
console.error(e);
}
} finally {
setInitialDataLoading(false);
}
}
}
async function getOfficesOptionsHandler() {
setLoadingOfficesOptions(true);
const res = await loadOffices();
const options = res.map((elem) => elem && { value: elem.id, label: elem.name });
setOfficesOptions(options);
setLoadingOfficesOptions(false);
try {
const res = await loadOffices();
const options = res.map((elem) => elem && { value: elem.id, label: elem.name });
setOfficesOptions(options);
} catch (e) {
if (e instanceof ApiError) {
notification.error({ description: e.message });
}
} finally {
setLoadingOfficesOptions(false);
}
}
async function getRelatedGroupsHandler() {
if (companyGroupId) {
setLoadingRelatedGroupsOptions(true);
if (!companyGroupId) return;
setLoadingRelatedGroupsOptions(true);
try {
const res = await fetchRelatedGroups(companyGroupId);
const gsks = res.filter((elem) => elem.kind === 'gsk');
const gszs = res.filter((elem) => elem.kind === 'gsz');
setGskData(gsks);
setGszData(gszs);
} catch (e) {
if (e instanceof ApiError) {
notification.error({ description: e.message });
}
} finally {
setLoadingRelatedGroupsOptions(false);
}
}
@ -81,15 +103,20 @@ export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId
const values = await form.validateFields();
await onOk({
...values,
kpp: type === 'ИП' ? undefined : values.kpp?.toString(),
kpp: type === 'ИП' ? null : values.kpp?.toString(),
inn: jurId ? undefined : values?.inn?.toString(),
company_group_id: jurId ? undefined : values.company_group_id,
gsz_id: values.gsz_id ? values?.gsz_id : null,
gsk_id: values.gsk_id ? values?.gsk_id : null,
regional_office_id: values.regional_office_id ? values?.regional_office_id : null,
});
} catch (e) {
if (e instanceof ApiError) {
notification.error({
description: e.message,
});
} else if (e instanceof Error && e.name !== 'ValidationError') {
console.error(e);
}
} finally {
setConfirmLoading(false);
@ -112,7 +139,12 @@ export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId
useEffect(() => {
getOfficesOptionsHandler();
}, []);
useEffect(() => {
form.setFieldsValue({
gsk_id: undefined,
gsz_id: undefined,
});
getRelatedGroupsHandler();
}, [companyGroupId]);
@ -122,7 +154,7 @@ export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId
open={open}
onCancel={handleCancel}
onOk={handleOk}
okText={jurId ? 'Сохраить' : 'Добавить'}
okText={jurId ? 'Сохранить' : 'Добавить'}
cancelText='Отмена'
destroyOnHidden
width={720}
@ -145,7 +177,7 @@ export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId
{ pattern: /^\d{10}$/, message: '10 цифр' },
]
}>
<InputNumber
<Input
disabled={!!jurId}
style={{ width: '100%' }}
placeholder={type === 'ИП' ? '000000000000' : '0000000000'}
@ -154,13 +186,13 @@ export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId
</Form.Item>
</Col>
<Col span={6}>
<Form.Item name='kpp' label='КПП' rules={[{ pattern: /^\d{9}$/, message: '9 цифр' }]}>
<InputNumber placeholder='000000000' maxLength={9} disabled={type === 'ИП'} style={{ width: '100%' }} />
<Form.Item name='kpp' label='КПП' rules={[{ pattern: /^[0-9]{4}[0-9A-Z]{2}[0-9]{3}$/, message: 'Некорректный формат' }]}>
<Input placeholder='000000000' maxLength={9} disabled={type === 'ИП'} style={{ width: '100%' }} />
</Form.Item>
</Col>
<Col span={6}>
<Form.Item name='crm_id' label='ID ЮЛ в CRM' rules={[{ len: 11, message: 'Должно быть 11 символов' }]}>
<Input maxLength={11} />
<Form.Item name='crm_id' label='ID ЮЛ в CRM'>
<Input />
</Form.Item>
</Col>
<Col span={6}>

View File

@ -54,7 +54,7 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur
const [jurId, setJurId] = useState('');
const filterdData = useMemo(() => {
if (relatedGroupFilter?.id) {
if (relatedGroupFilter?.id && !outside_group) {
return rawRows?.filter((row) => {
return row?.memberships?.some((member) => member.related_group_id === relatedGroupFilter.id);
});
@ -243,7 +243,7 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur
<ColumnSettings defs={catalogueJurConfig.columns} visibleKeys={visibleKeys} onChange={setVisibleKeys} />
</Space>
</Space>
{relatedGroupFilter?.id && (
{(relatedGroupFilter?.id && !outside_group) && (
<div
style={{
display: 'flex',
@ -269,7 +269,7 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur
<span style={{ color: '#874d00' }}>Фильтр по:</span>
<span style={{ fontWeight: 600, color: '#ad4e00' }}>{relatedGroupFilter.code}</span>
<span style={{ color: '#874d00' }}>
— {filterdData?.length}
— {filterdData?.length} &nbsp;
{pluralRu(filterdData?.length ?? 0, ['запись', 'записи', 'записей'])}
</span>
</div>

View File

@ -12,8 +12,10 @@ export const catalogueJurConfig: TableConfig<ICatalogueJur> = {
title: 'Статус',
features: { sort: true },
render: (_: unknown, row) => {
// #TODO поменять логику если запись не активна
return <TableTag text={!row.closed ? 'Активно' : 'Не активно'} {...TAG_PRESETS.green} />;
const preset = !row.closed ? TAG_PRESETS.green : TAG_PRESETS.gray;
const text = !row.closed ? 'Активно' : 'Не активно';
return <TableTag text={text} {...preset} />;
},
},
{

View File

@ -26,10 +26,17 @@ export const CompanyGroupForm: React.FC<Props> = ({ open, onCancel, onOk }) => {
async function getOfficesOptionsHandler() {
setLoadingOptions(true);
const res = await loadOffices();
const options = res.map((elem) => elem && { value: elem.id, label: elem.name });
setOfficesOptions(options);
setLoadingOptions(false);
try {
const res = await loadOffices();
const options = res.map((elem) => elem && { value: elem.id, label: elem.name });
setOfficesOptions(options);
} catch (e) {
if (e instanceof ApiError) {
notification.error({ description: e.message });
}
} finally {
setLoadingOptions(false);
}
}
const handleOk = async () => {
@ -45,6 +52,8 @@ export const CompanyGroupForm: React.FC<Props> = ({ open, onCancel, onOk }) => {
notification.error({
description: e.message,
});
} else if (e instanceof Error && e.name !== 'ValidationError') {
console.error(e);
}
} finally {
setConfirmLoading(false);
@ -78,8 +87,8 @@ export const CompanyGroupForm: React.FC<Props> = ({ open, onCancel, onOk }) => {
<Row gutter={16}>
<Col span={12}>
<Form.Item name='crm_id' label='ID ГК в CRM' rules={[{ len: 11, message: 'Должно быть 11 символов' }]}>
<Input maxLength={11} placeholder='Генерируется автоматически' />
<Form.Item name='crm_id' label='ID ГК в CRM'>
<Input placeholder='Генерируется автоматически' />
</Form.Item>
</Col>
<Col span={12}>

View File

@ -1,10 +1,11 @@
import { FolderOpenOutlined, SearchOutlined } from '@ant-design/icons';
import { Empty, Input, Listy, Spin, Tag, Typography } from 'antd';
import { useEffect, useMemo, useState } from 'react';
import { setActiveCompanyGroup } from '../../store/slices/companyGroupsSlice/companyGroupsSlice';
import { getCompanyGroupsThunk } from '../../store/slices/companyGroupsSlice/thunks';
import { Input, List, Spin, Empty, Typography, Tag } from 'antd';
import { FolderOpenOutlined, SearchOutlined } from '@ant-design/icons';
import { useAppDispatch, useAppSelector } from '../../store/store';
import './CompanyGroupsList.css';
import { getCompanyGroupsThunk } from '../../store/slices/companyGroupsSlice/thunks';
import { setActiveCompanyGroup } from '../../store/slices/companyGroupsSlice/companyGroupsSlice';
import { useVirtualList } from '../../hooks/useVirtualList';
const { Text } = Typography;
export const CompanyGroupsList = () => {
@ -22,10 +23,22 @@ export const CompanyGroupsList = () => {
return rawRows.filter((g) => g.name.toLowerCase().includes(q) || g.crm_id?.toLowerCase().includes(q));
}, [rawRows, query]);
const { ref, onScroll, visibleItems, totalHeight, offsetY } = useVirtualList(filtered, {
itemHeight: 56,
containerHeight: 900,
overscan: 5,
});
useEffect(() => {
dispatch(getCompanyGroupsThunk());
}, [dispatch]);
useEffect(() => {
if (!activeCompanyGroup && rawRows?.length) {
dispatch(setActiveCompanyGroup(rawRows?.[0]));
}
}, [rawRows, activeCompanyGroup, dispatch]);
return (
<div
style={{
@ -36,7 +49,7 @@ export const CompanyGroupsList = () => {
borderRight: '1px solid #f0f0f0',
borderRadius: 12,
}}>
<div style={{ padding: '12px 16px', borderBottom: '1px solid #0f172a0f' }}>
<div style={{ padding: 12 }}>
<Input
allowClear
prefix={<SearchOutlined style={{ color: '#bfbfbf' }} />}
@ -46,124 +59,100 @@ export const CompanyGroupsList = () => {
/>
</div>
<div style={{ flex: 1, overflowY: 'auto', padding: '10px' }}>
{loading && (
<div ref={ref} onScroll={onScroll} style={{ flex: 1, overflowY: 'auto', padding: '0 8px 8px' }}>
{loading ? (
<div style={{ textAlign: 'center', padding: 24 }}>
<Spin />
</div>
)}
{!loading && filtered.length === 0 && (
) : filtered.length === 0 ? (
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description='Компании и организации не найдены' style={{ marginTop: 32 }} />
)}
{!loading && filtered.length > 0 && (
<Listy
virtual
rowKey='id'
items={filtered}
height={900}
itemRender={(item) => {
const active = item.id === activeCompanyGroup?.id;
return (
<button
type='button'
onClick={() => dispatch(setActiveCompanyGroup(item))}
style={{
display: 'block',
width: '100%',
border: 0,
font: 'inherit',
textAlign: 'left',
cursor: 'pointer',
borderRadius: 8,
padding: '10px 12px',
marginBottom: 4,
background: active ? '#e6f4ea' : 'transparent',
boxShadow: active ? 'inset 0 0 0 1px #2ea64b3d, inset 3px 0 0 #258141' : 'inset 0 0 0 1px #0f172a14',
transition: 'background 0.15s',
borderBottom: 0,
}}
onMouseEnter={(e) => {
if (!active) {
(e.currentTarget as HTMLElement).style.background = '#fafafa';
}
}}
onMouseLeave={(e) => {
if (!active) {
(e.currentTarget as HTMLElement).style.background = 'transparent';
}
}}>
<div
style={{
display: 'flex',
alignItems: 'center',
width: '100%',
gap: 12,
minWidth: 0,
}}>
<Tag
) : (
<div style={{ height: totalHeight, position: 'relative' }}>
<div style={{ transform: `translateY(${offsetY}px)` }}>
<List
dataSource={visibleItems}
split={false}
renderItem={({item}) => {
const active = item.id === activeCompanyGroup?.id;
return (
<List.Item
onClick={() => dispatch(setActiveCompanyGroup(item))}
style={{
cursor: 'pointer',
borderRadius: 8,
width: 28,
height: 28,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '10px 12px',
marginBottom: 4,
background: active ? '#e6f4ea' : 'transparent',
boxShadow: active ? 'inset 0 0 0 1px #2ea64b3d, inset 3px 0 0 #258141' : 'inset 0 0 0 1px #0f172a14',
transition: 'background 0.15s',
}}
color='success'>
<FolderOpenOutlined
style={{
fontSize: 18,
color: 'green',
flexShrink: 0,
}}
/>
</Tag>
<div style={{ flex: 1, minWidth: 0 }}>
<Text
strong
ellipsis
style={{
display: 'block',
fontSize: 14,
lineHeight: '20px',
}}>
{item.name}
</Text>
<Text
type='secondary'
ellipsis
style={{
display: 'block',
fontSize: 12,
lineHeight: '16px',
}}>
CRM ID: {item.crm_id ?? '-'}
</Text>
</div>
<Tag
style={{
margin: 0,
borderRadius: 10,
background: '#f5f5f5',
border: 'none',
color: '#595959',
fontWeight: 500,
minWidth: 24,
height: 20,
lineHeight: '20px',
textAlign: 'center',
padding: '0 8px',
flexShrink: 0,
onMouseEnter={(e) => {
if (!active) {
(e.currentTarget as HTMLElement).style.background = '#fafafa';
}
}}
onMouseLeave={(e) => {
if (!active) {
(e.currentTarget as HTMLElement).style.background = 'transparent';
}
}}>
{item.legal_entities_count}
</Tag>
</div>
</button>
);
}}
/>
<div
style={{
display: 'flex',
alignItems: 'center',
width: '100%',
gap: 12,
minWidth: 0,
}}>
<FolderOpenOutlined style={{ fontSize: 18, color: '#8c8c8c', flexShrink: 0 }} />
<div style={{ flex: 1, minWidth: 0 }}>
<Text
strong
ellipsis
style={{
display: 'block',
fontSize: 14,
lineHeight: '20px',
}}>
{item.name}
</Text>
<Text
type='secondary'
ellipsis
style={{
display: 'block',
fontSize: 12,
lineHeight: '16px',
}}>
CRM ID: {item.crm_id ?? '-'}
</Text>
</div>
<Tag
style={{
margin: 0,
borderRadius: 10,
background: '#f5f5f5',
border: 'none',
color: '#595959',
fontWeight: 500,
minWidth: 24,
height: 20,
lineHeight: '20px',
textAlign: 'center',
padding: '0 8px',
flexShrink: 0,
}}>
{item.legal_entities_count}
</Tag>
</div>
</List.Item>
);
}}
/>
</div>
</div>
)}
</div>
</div>

View File

@ -5,9 +5,10 @@ type Props = {
onCancel: () => void;
onOk: () => void | Promise<void>;
loading?: boolean;
kind: 'gsk' | 'gsz';
};
export const DeleteRelatedGroupModal: React.FC<Props> = ({ open, onCancel, onOk, loading }) => {
export const DeleteRelatedGroupModal: React.FC<Props> = ({ open, onCancel, onOk, loading, kind }) => {
return (
<Modal
title='Удалить?'
@ -19,7 +20,7 @@ export const DeleteRelatedGroupModal: React.FC<Props> = ({ open, onCancel, onOk,
okButtonProps={{ danger: true }}
confirmLoading={loading}
centered>
<p style={{ margin: 0, color: '#595959' }}>Группа связанных компаний будет удалена.</p>
<p style={{ margin: 0, color: '#595959' }}>Группа связанных {kind === 'gsk' ? 'компаний' : 'заёмщиков'} будет удалена.</p>
</Modal>
);
};

View File

@ -36,15 +36,22 @@ export const MoveCatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, ju
async function getInitialData() {
setInitialDataLoading(true);
const data = await fetchOneCatalogueJur(jurId);
form.setFieldsValue({
name: data?.name,
company_group_name: data?.company_group_name ?? '',
old_company_group_id: data?.company_group_id ?? '',
company_group_id: undefined,
effective_date: '',
});
setInitialDataLoading(false);
try {
const data = await fetchOneCatalogueJur(jurId);
form.setFieldsValue({
name: data?.name,
company_group_name: data?.company_group_name ?? '',
old_company_group_id: data?.company_group_id ?? '',
company_group_id: undefined,
effective_date: '',
});
} catch (e) {
if (e instanceof ApiError) {
notification.error({ description: e.message });
}
} finally {
setInitialDataLoading(false);
}
}
const handleOk = async () => {

View File

@ -36,7 +36,7 @@ export const RelatedGroupForm: React.FC<Props> = ({ open, onCancel, onOk, relate
form.setFieldsValue({
crm_id: data?.crm_id,
name: data?.name,
created_date: data?.created_date,
created_date: data?.created_date ?? dayjs().format('YYYY-MM-DD'),
company_group_id: data?.company_group_id,
});
} catch (e) {
@ -53,7 +53,7 @@ export const RelatedGroupForm: React.FC<Props> = ({ open, onCancel, onOk, relate
try {
const { created_date, name, crm_id, company_group_id } = await form.validateFields();
await onOk({
created_date,
created_date: created_date ?? dayjs().format('YYYY-MM-DD'),
name,
crm_id,
company_group_id: relatedGroupId ? undefined : company_group_id,
@ -85,7 +85,7 @@ export const RelatedGroupForm: React.FC<Props> = ({ open, onCancel, onOk, relate
return (
<Modal
title={`${relatedGroupId ? 'Изменить' : 'Создать'} группу связанных ${kind === 'gsk' ? 'компаний' : 'заемщииков'}`}
title={`${relatedGroupId ? 'Изменить' : 'Создать'} группу связанных ${kind === 'gsk' ? 'компаний' : 'заемщиков'}`}
open={open}
onCancel={handleCancel}
onOk={handleOk}
@ -95,8 +95,8 @@ export const RelatedGroupForm: React.FC<Props> = ({ open, onCancel, onOk, relate
loading={initialDataLoading}
confirmLoading={confirmLoading}>
<Form form={form} layout='vertical'>
<FormItem name='crm_id' label='ID в CRM' rules={[{ len: 11, message: 'Должно быть 11 символов' }]}>
<Input maxLength={11} placeholder='Генерируется автоматически' />
<FormItem name='crm_id' label='ID в CRM'>
<Input placeholder='Генерируется автоматически' />
</FormItem>
<FormItem name='name' label='Наименование' rules={[{ required: true, message: 'Укажите наименование' }]}>
<Input />
@ -115,7 +115,6 @@ export const RelatedGroupForm: React.FC<Props> = ({ open, onCancel, onOk, relate
<Form.Item
name='created_date'
label='Дата создания'
rules={[{ required: true, message: 'Укажите дату' }]}
getValueProps={(value: string | undefined) => ({
value: value ? dayjs(value) : undefined,
})}

View File

@ -180,6 +180,7 @@ export function RelatedGroupTable({ tabsComponent, data, loading, getData, activ
loading={deletingLoading}
onCancel={() => closeDeleteRelatedGroupHandler()}
onOk={deleteRelatedGroupHandler}
kind={activeTab}
/>
)}
</div>

View File

@ -34,14 +34,21 @@ export const WithdrawCatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk
async function getInitialData() {
setInitialDataLoading(true);
const data = await fetchOneCatalogueJur(jurId);
form.setFieldsValue({
name: data?.name,
event: undefined,
effective_date: '',
comment: '',
});
setInitialDataLoading(false);
try {
const data = await fetchOneCatalogueJur(jurId);
form.setFieldsValue({
name: data?.name,
event: undefined,
effective_date: '',
comment: '',
});
} catch (e) {
if (e instanceof ApiError) {
notification.error({ description: e.message });
}
} finally {
setInitialDataLoading(false);
}
}
const handleOk = async () => {
@ -100,7 +107,7 @@ export const WithdrawCatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk
<DatePicker minDate={dayjs()} style={{ width: '100%' }} format='DD.MM.YYYY' placeholder='ДД.ММ.ГГГГ' />
</Form.Item>
<FormItem name='comment' label='Комментарий'>
<TextArea maxLength={6} rows={4} placeholder='Необязательно' />
<TextArea rows={4} placeholder='Необязательно' />
</FormItem>
</Form>
</Modal>