diff --git a/web/src/App.css b/web/src/App.css index e69de29..606dd57 100644 --- a/web/src/App.css +++ b/web/src/App.css @@ -0,0 +1,7 @@ +/* Теги выбранных значений в селектах: фильтр шахматки, синонимы ЮЛ */ +.custom-select-selection-item .ant-select-selection-item { + background-color: #ecfdf3 !important; + color: #1f5f35 !important; + box-shadow: inset 0 0 0 1px #2ea64b38 !important; + border-radius: 999px !important; +} diff --git a/web/src/layouts/CatalogueGroups.tsx b/web/src/layouts/CatalogueGroups.tsx index 9509c4a..6d712ea 100644 --- a/web/src/layouts/CatalogueGroups.tsx +++ b/web/src/layouts/CatalogueGroups.tsx @@ -6,8 +6,8 @@ import PageTitle from '../components/PageTitle'; import { createCatalogueJur } from '../services/api/directories/catalogue_jur'; import { createCompanyGroup, fetchRelatedGroups } from '../services/api/directories/company_groups'; import { createRelatedGroup } from '../services/api/directories/related-groups'; +import { setActiveCompanyGroup } from '../store/slices/catalogueJurSlice/catalogueJurSlice'; import { getCatalogueJurThunk } from '../store/slices/catalogueJurSlice/thunks'; -import { setActiveCompanyGroup } from '../store/slices/companyGroupsSlice/companyGroupsSlice'; import { getCompanyGroupsThunk } from '../store/slices/companyGroupsSlice/thunks'; import { useAppDispatch, useAppSelector } from '../store/store'; import type { RelatedGroupOut } from '../types/api'; @@ -37,61 +37,37 @@ export function CatalogueGroup() { const [activeTab, setActiveTab] = useState('legal_entities'); const [gskData, setGskData] = useState([]); const [gszData, setGszData] = useState([]); - const activeCompanyGroup = useAppSelector((state) => state.company_groups.activeCompanyGroup); + const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup); const relatedGroupFilter = useAppSelector((state) => state.catalogue_jur.relatedGroupFilter); const rawRows = useAppSelector((state) => state.company_groups.raw_rows); async function createJurHandler(values: CatalogueJurFormProps) { - try { - await createCatalogueJur(values); - dispatch(getCompanyGroupsThunk()); - dispatch( - getCatalogueJurThunk({ - closed: isGettingArchive, - outside_group: false, - company_group_id: activeCompanyGroup?.id, - }), - ); - setKindForm(null); - } catch (e) { - if (e instanceof ApiError) { - notification.error({ - description: e.message, - }); - } - } + await createCatalogueJur(values); + dispatch(getCompanyGroupsThunk()); + dispatch( + getCatalogueJurThunk({ + closed: isGettingArchive, + outside_group: false, + company_group_id: activeCompanyGroup?.id, + }), + ); + setKindForm(null); } async function createRelatedGroupHandler(values: RelatedGroupFormType) { if (values.company_group_id) { - try { - await createRelatedGroup(values.company_group_id, { - ...values, - company_group_id: undefined, - }); - getRelatedGroupsHandler(); - setKindForm(null); - } catch (e) { - if (e instanceof ApiError) { - notification.error({ - description: e.message, - }); - } - } + await createRelatedGroup(values.company_group_id, { + ...values, + company_group_id: undefined, + }); + getRelatedGroupsHandler(); + setKindForm(null); } } async function createCompanyGroupHandler(values: CreateCompanyGroupProps) { - try { - await createCompanyGroup(values); - dispatch(getCompanyGroupsThunk()); - getRelatedGroupsHandler(); - setKindForm(null); - } catch (e) { - if (e instanceof ApiError) { - notification.error({ - description: e.message, - }); - } - } + await createCompanyGroup(values); + dispatch(getCompanyGroupsThunk()); + getRelatedGroupsHandler(); + setKindForm(null); } async function getRelatedGroupsHandler() { @@ -105,9 +81,7 @@ export function CatalogueGroup() { setGszData(gszs); } catch (e) { if (e instanceof ApiError) { - notification.error({ - description: e.message, - }); + notification.error({ description: e.message }); } } finally { setRelatedGroupLoading(false); @@ -119,16 +93,17 @@ export function CatalogueGroup() { getRelatedGroupsHandler(); }, [activeCompanyGroup]); + // Без выбранной ГК таблица ЮЛ не грузится — выбираем первую ГК списка + useEffect(() => { + if (!activeCompanyGroup && rawRows?.length) { + dispatch(setActiveCompanyGroup(rawRows[0])); + } + }, [rawRows, activeCompanyGroup, dispatch]); + useEffect(() => { setActiveTab('legal_entities'); }, [relatedGroupFilter]); - useEffect(() => { - if (!activeCompanyGroup && rawRows?.length) { - dispatch(setActiveCompanyGroup(rawRows?.[0])); - } - }, [rawRows, activeCompanyGroup]); - return (
{ setKindForm(null); }} - onOk={async (values) => { - await createJurHandler(values); - }} + onOk={createJurHandler} /> )} {(kindForm === 'gsk' || kindForm === 'gsz') && ( @@ -215,9 +188,7 @@ export function CatalogueGroup() { onCancel={() => { setKindForm(null); }} - onOk={async (values) => { - await createRelatedGroupHandler(values); - }} + onOk={createRelatedGroupHandler} /> )} {kindForm === 'gk' && ( @@ -226,9 +197,7 @@ export function CatalogueGroup() { onCancel={() => { setKindForm(null); }} - onOk={async (values) => { - await createCompanyGroupHandler(values); - }} + onOk={createCompanyGroupHandler} /> )}
diff --git a/web/src/layouts/CatalogueJur.tsx b/web/src/layouts/CatalogueJur.tsx index 3b2ac3b..8919f11 100644 --- a/web/src/layouts/CatalogueJur.tsx +++ b/web/src/layouts/CatalogueJur.tsx @@ -1,41 +1,30 @@ import { PlusOutlined } from '@ant-design/icons'; import { Button, Space } from 'antd'; import { useState } from 'react'; -import { ApiError } from '../api/client'; import PageTitle from '../components/PageTitle'; import { createCatalogueJur } from '../services/api/directories/catalogue_jur'; import { getCatalogueJurThunk } from '../store/slices/catalogueJurSlice/thunks'; import { useAppDispatch, useAppSelector } from '../store/store'; import type { CatalogueJurFormProps } from '../types/catalogueJur/catalogueJur'; -import { useNotificationApi } from '../utils/useNotification'; import { CatalogueJurForm } from '../widgets/CatalogueJurForm/CatalogueJurForm'; import { CatalogueJurTable } from '../widgets/CatalogueJurTable/CatalogueJurTable'; export function CatalogueJur() { const dispatch = useAppDispatch(); - const notification = useNotificationApi(); const isGettingArchive = useAppSelector((state) => state.catalogue_jur.isGettingArchive); const [createFormOpen, setCreateFormOpen] = useState(false); const outside_group = true; async function createJurHandler(values: CatalogueJurFormProps) { - try { - await createCatalogueJur(values); - dispatch( - getCatalogueJurThunk({ - closed: isGettingArchive, - outside_group: outside_group, - }), - ); - setCreateFormOpen(false); - } catch (e) { - if (e instanceof ApiError) { - notification.error({ - description: e.message, - }); - } - } + await createCatalogueJur(values); + dispatch( + getCatalogueJurThunk({ + closed: isGettingArchive, + outside_group: outside_group, + }), + ); + setCreateFormOpen(false); } return ( @@ -59,9 +48,7 @@ export function CatalogueJur() { onCancel={() => { setCreateFormOpen(false); }} - onOk={async (values) => { - await createJurHandler(values); - }} + onOk={createJurHandler} /> )} diff --git a/web/src/store/slices/catalogueJurSlice/catalogueJurSlice.ts b/web/src/store/slices/catalogueJurSlice/catalogueJurSlice.ts index 7a14e25..7abf90b 100644 --- a/web/src/store/slices/catalogueJurSlice/catalogueJurSlice.ts +++ b/web/src/store/slices/catalogueJurSlice/catalogueJurSlice.ts @@ -1,5 +1,7 @@ import { type PayloadAction, createSlice } from '@reduxjs/toolkit'; import type { RelatedGroupOut } from '../../../types/api'; +import type { ICompanyGroup } from '../../../types/companyGroups/companyGroups'; +import { getCompanyGroupsThunk } from '../companyGroupsSlice/thunks'; import { getCatalogueJurThunk } from './thunks'; import type { CatalogueJurSliceType } from './types'; @@ -10,6 +12,7 @@ const initialState: CatalogueJurSliceType = { error: null, isGettingArchive: false, relatedGroupFilter: null, + activeCompanyGroup: null, }; const catalogueJurSlice = createSlice({ @@ -22,6 +25,10 @@ const catalogueJurSlice = createSlice({ setRelatedGroupFilter(state, action: PayloadAction) { state.relatedGroupFilter = action.payload; }, + setActiveCompanyGroup(state, action: PayloadAction) { + state.activeCompanyGroup = action.payload; + state.relatedGroupFilter = null; + }, }, extraReducers: (builder) => { builder @@ -37,8 +44,15 @@ const catalogueJurSlice = createSlice({ .addCase(getCatalogueJurThunk.rejected, (state, action) => { state.error = action.payload ?? 'Неизвестная ошибка'; state.loading = false; + }) + // Выбранная ГК — копия строки списка ГК: после перезагрузки списка берём свежую (счётчик ЮЛ в шапке и вкладке) + .addCase(getCompanyGroupsThunk.fulfilled, (state, action) => { + if (state.activeCompanyGroup?.id) { + state.activeCompanyGroup = action.payload.find((elem) => elem.id === state.activeCompanyGroup?.id) ?? null; + } }); }, }); -export const { setIsGettingArchive, setRelatedGroupFilter } = catalogueJurSlice.actions; + +export const { setIsGettingArchive, setRelatedGroupFilter, setActiveCompanyGroup } = catalogueJurSlice.actions; export default catalogueJurSlice.reducer; diff --git a/web/src/store/slices/catalogueJurSlice/types.ts b/web/src/store/slices/catalogueJurSlice/types.ts index 0ed8c2b..7227c33 100644 --- a/web/src/store/slices/catalogueJurSlice/types.ts +++ b/web/src/store/slices/catalogueJurSlice/types.ts @@ -1,5 +1,6 @@ import type { RelatedGroupOut } from '../../../types/api'; import type { ICatalogueJur } from '../../../types/catalogueJur/catalogueJur'; +import type { ICompanyGroup } from '../../../types/companyGroups/companyGroups'; export interface CatalogueJurSliceType { total_groups: number; @@ -8,6 +9,7 @@ export interface CatalogueJurSliceType { error: string | null; isGettingArchive: boolean; relatedGroupFilter?: RelatedGroupOut | null; + activeCompanyGroup?: ICompanyGroup | null; } export interface GetCatalogueJurPropsI { diff --git a/web/src/store/slices/companyGroupsSlice/companyGroupsSlice.ts b/web/src/store/slices/companyGroupsSlice/companyGroupsSlice.ts index c298b6a..c56a483 100644 --- a/web/src/store/slices/companyGroupsSlice/companyGroupsSlice.ts +++ b/web/src/store/slices/companyGroupsSlice/companyGroupsSlice.ts @@ -1,5 +1,4 @@ -import { type PayloadAction, createSlice } from '@reduxjs/toolkit'; -import type { ICompanyGroup } from '../../../types/companyGroups/companyGroups'; +import { createSlice } from '@reduxjs/toolkit'; import { getCompanyGroupsThunk } from './thunks'; import type { CompanyGroupSliceType } from './types'; @@ -8,17 +7,12 @@ const initialState: CompanyGroupSliceType = { total_groups: 0, loading: false, error: null, - activeCompanyGroup: null, }; const comGroupsSlice = createSlice({ name: 'company_groups', initialState, - reducers: { - setActiveCompanyGroup(state, action: PayloadAction) { - state.activeCompanyGroup = action.payload; - }, - }, + reducers: {}, extraReducers: (builder) => { builder .addCase(getCompanyGroupsThunk.pending, (state) => { @@ -27,10 +21,6 @@ const comGroupsSlice = createSlice({ }) .addCase(getCompanyGroupsThunk.fulfilled, (state, action) => { state.raw_rows = action.payload; - if (state.activeCompanyGroup?.id) { - const newActiveCompanyGroup = action.payload.find((elem) => elem.id === state.activeCompanyGroup?.id); - state.activeCompanyGroup = newActiveCompanyGroup; - } state.total_groups = action.payload.length; state.loading = false; }) @@ -40,5 +30,4 @@ const comGroupsSlice = createSlice({ }); }, }); -export const { setActiveCompanyGroup } = comGroupsSlice.actions; export default comGroupsSlice.reducer; diff --git a/web/src/store/slices/companyGroupsSlice/types.ts b/web/src/store/slices/companyGroupsSlice/types.ts index 7a49aa3..5f35cfa 100644 --- a/web/src/store/slices/companyGroupsSlice/types.ts +++ b/web/src/store/slices/companyGroupsSlice/types.ts @@ -5,5 +5,4 @@ export interface CompanyGroupSliceType { raw_rows: ICompanyGroup[]; loading: boolean; error: string | null; - activeCompanyGroup?: ICompanyGroup | null; } diff --git a/web/src/types/api.ts b/web/src/types/api.ts index 0956c4f..7e36dd4 100644 --- a/web/src/types/api.ts +++ b/web/src/types/api.ts @@ -375,6 +375,7 @@ export interface ConsolidationCreate { export interface RelatedGroupOut { id: string; code: string; + crm_id: string | null; company_group_id: string; kind: 'gsk' | 'gsz'; name: string; @@ -389,7 +390,6 @@ export interface RelatedGroupMemberOut { } export interface RelatedGroupDetail extends RelatedGroupOut { members: RelatedGroupMemberOut[]; - crm_id: string; } export interface LegalEntityBrief { id: string; diff --git a/web/src/types/relatedGroup/relatedGroup.ts b/web/src/types/relatedGroup/relatedGroup.ts index 7472809..82cfb1c 100644 --- a/web/src/types/relatedGroup/relatedGroup.ts +++ b/web/src/types/relatedGroup/relatedGroup.ts @@ -1,7 +1,7 @@ export type RelatedGroupFormType = { name: string; created_date: string | null; - crm_id: string; + crm_id: string | null; kind?: 'gsk' | 'gsz'; company_group_id?: string; }; diff --git a/web/src/widgets/CataloguGroupTabs/CataloguGroupTabs.tsx b/web/src/widgets/CataloguGroupTabs/CataloguGroupTabs.tsx index 636ea7d..679e474 100644 --- a/web/src/widgets/CataloguGroupTabs/CataloguGroupTabs.tsx +++ b/web/src/widgets/CataloguGroupTabs/CataloguGroupTabs.tsx @@ -12,7 +12,7 @@ interface CataloguGroupTabsI { export type CatalogueGroupTabKey = 'legal_entities' | 'gsk' | 'gsz'; export const CataloguGroupTabs = ({ activeTab, setActiveTab, gskData, gszData }: CataloguGroupTabsI) => { - const activeCompanyGroup = useAppSelector((state) => state.company_groups.activeCompanyGroup); + const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup); return ( { - const activeCompanyGroup = useAppSelector((state) => state.company_groups.activeCompanyGroup); + const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup); const count = activeCompanyGroup?.legal_entities_count ?? 0; const organizationWord = pluralRu(count, ['организация', 'организации', 'организаций']); diff --git a/web/src/widgets/CatalogueJurForm/CatalogueJurForm.tsx b/web/src/widgets/CatalogueJurForm/CatalogueJurForm.tsx index bd865e0..2a78176 100644 --- a/web/src/widgets/CatalogueJurForm/CatalogueJurForm.tsx +++ b/web/src/widgets/CatalogueJurForm/CatalogueJurForm.tsx @@ -17,6 +17,14 @@ type Props = { jurId?: string; }; +// Ошибки сервера, относящиеся к одному полю, показываем у этого поля +const FIELD_BY_ERROR_CODE: Record = { + INN_EXISTS: 'inn', + INVALID_INN: 'inn', + INVALID_KPP: 'kpp', + CRM_ID_EXISTS: 'crm_id', +}; + export const CatalogueJurForm: React.FC = ({ open, onCancel, onOk, jurId }) => { const [form] = Form.useForm(); const notification = useNotificationApi(); @@ -27,12 +35,11 @@ export const CatalogueJurForm: React.FC = ({ open, onCancel, onOk, jurId const [loadingOfficesOptions, setLoadingOfficesOptions] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false); const [officesOptions, setOfficesOptions] = useState<{ value: string; label: string }[]>([]); - const companyGrops = useAppSelector((state) => state.company_groups.raw_rows); const companyGropsLoading = useAppSelector((state) => state.company_groups.loading); + const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup); const type = Form.useWatch('entity_type', form); - const companyGroupId = Form.useWatch('company_group_id', form); async function getInitialData() { if (jurId) { @@ -51,6 +58,7 @@ export const CatalogueJurForm: React.FC = ({ open, onCancel, onOk, jurId gsk_id: data.memberships?.find((elem) => elem.kind === 'gsk')?.related_group_id, gsz_id: data.memberships?.find((elem) => elem.kind === 'gsz')?.related_group_id, }); + getRelatedGroupsHandler(data.company_group_id as string); } catch (e) { if (e instanceof ApiError) { notification.error({ description: e.message }); @@ -58,6 +66,11 @@ export const CatalogueJurForm: React.FC = ({ open, onCancel, onOk, jurId } finally { setInitialDataLoading(false); } + } else { + form.setFieldsValue({ + company_group_id: activeCompanyGroup?.id ?? undefined, + }); + getRelatedGroupsHandler(activeCompanyGroup?.id ?? ''); } } @@ -76,12 +89,12 @@ export const CatalogueJurForm: React.FC = ({ open, onCancel, onOk, jurId } } - async function getRelatedGroupsHandler() { - if (!companyGroupId) return; + async function getRelatedGroupsHandler(companyId: string) { + if (!companyId) return; setLoadingRelatedGroupsOptions(true); try { - const res = await fetchRelatedGroups(companyGroupId); + const res = await fetchRelatedGroups(companyId); const gsks = res.filter((elem) => elem.kind === 'gsk'); const gszs = res.filter((elem) => elem.kind === 'gsz'); setGskData(gsks); @@ -101,18 +114,21 @@ export const CatalogueJurForm: React.FC = ({ open, onCancel, onOk, jurId const values = await form.validateFields(); await onOk({ ...values, - kpp: type === 'ИП' ? null : values.kpp?.toString(), + kpp: type === 'ИП' ? null : (values.kpp?.toString() ?? null), 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, + crm_id: values.crm_id ?? null, }); } catch (e) { if (e instanceof ApiError) { - notification.error({ - description: e.message, - }); + const field = e.code ? FIELD_BY_ERROR_CODE[e.code] : undefined; + if (field) { + form.setFields([{ name: field, errors: [e.message] }]); + } + notification.error({ description: e.message }); } } finally { setConfirmLoading(false); @@ -128,21 +144,13 @@ export const CatalogueJurForm: React.FC = ({ open, onCancel, onOk, jurId return companyGrops?.map((company) => company && { value: company.id, label: company.name }); }, [companyGrops]); - useEffect(() => { - getInitialData(); - }, [jurId, open]); - useEffect(() => { getOfficesOptionsHandler(); }, []); useEffect(() => { - form.setFieldsValue({ - gsk_id: undefined, - gsz_id: undefined, - }); - getRelatedGroupsHandler(); - }, [companyGroupId]); + getInitialData(); + }, [jurId, open]); return ( = ({ open, onCancel, onOk, jurId - + value?.toUpperCase()} + rules={[{ pattern: /^[0-9]{4}[0-9A-Z]{2}[0-9]{3}$/, message: 'Некорректный формат' }]}> @@ -213,6 +225,7 @@ export const CatalogueJurForm: React.FC = ({ open, onCancel, onOk, jurId label='Альтернативные наименования' extra='Введите синоним и нажмите Enter. Можно добавить несколько значений.'> + diff --git a/web/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx b/web/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx index 16efc82..47d0caf 100644 --- a/web/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx +++ b/web/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx @@ -2,7 +2,7 @@ import { FolderOpenOutlined, SearchOutlined } from '@ant-design/icons'; import { Empty, Input, List, Spin, Tag, Typography } from 'antd'; import { useEffect, useMemo, useState } from 'react'; import { useVirtualList } from '../../hooks/useVirtualList'; -import { setActiveCompanyGroup } from '../../store/slices/companyGroupsSlice/companyGroupsSlice'; +import { setActiveCompanyGroup } from '../../store/slices/catalogueJurSlice/catalogueJurSlice'; import { getCompanyGroupsThunk } from '../../store/slices/companyGroupsSlice/thunks'; import { useAppDispatch, useAppSelector } from '../../store/store'; @@ -13,7 +13,7 @@ export const CompanyGroupsList = () => { const rawRows = useAppSelector((state) => state.company_groups.raw_rows); const loading = useAppSelector((state) => state.company_groups.loading); - const activeCompanyGroup = useAppSelector((state) => state.company_groups.activeCompanyGroup); + const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup); const [query, setQuery] = useState(''); diff --git a/web/src/widgets/ConsolidationChessTableFilter/ConsolidationChessTableFilter.css b/web/src/widgets/ConsolidationChessTableFilter/ConsolidationChessTableFilter.css deleted file mode 100644 index 8dacfcf..0000000 --- a/web/src/widgets/ConsolidationChessTableFilter/ConsolidationChessTableFilter.css +++ /dev/null @@ -1,7 +0,0 @@ -/* Теги выбранных значений в селектах фильтра шахматки */ -.custom-select-selection-item .ant-select-selection-item { - background-color: #ecfdf3 !important; - color: #1f5f35 !important; - box-shadow: inset 0 0 0 1px #2ea64b38 !important; - border-radius: 999px !important; -} diff --git a/web/src/widgets/ConsolidationChessTableFilter/ConsolidationChessTableFilter.tsx b/web/src/widgets/ConsolidationChessTableFilter/ConsolidationChessTableFilter.tsx index cf58c0c..d9ab17b 100644 --- a/web/src/widgets/ConsolidationChessTableFilter/ConsolidationChessTableFilter.tsx +++ b/web/src/widgets/ConsolidationChessTableFilter/ConsolidationChessTableFilter.tsx @@ -6,7 +6,6 @@ import { type OptionType, TreeFilterDropdown } from '../../components/TreeFilter import type { Account, MatrixCompany, Quarter } from '../../types/api'; import { quarterShortLabel } from '../../utils/labels'; import { useNotificationApi } from '../../utils/useNotification'; -import './ConsolidationChessTableFilter.css'; interface ConsolidationChessTableFilterI { companies: string[]; diff --git a/web/src/widgets/RelatedGroupForm/RelatedGroupForm.tsx b/web/src/widgets/RelatedGroupForm/RelatedGroupForm.tsx index 60d0f58..d4ed42e 100644 --- a/web/src/widgets/RelatedGroupForm/RelatedGroupForm.tsx +++ b/web/src/widgets/RelatedGroupForm/RelatedGroupForm.tsx @@ -26,9 +26,15 @@ export const RelatedGroupForm: React.FC = ({ open, onCancel, onOk, relate const [confirmLoading, setConfirmLoading] = useState(false); const companyGrops = useAppSelector((state) => state.company_groups.raw_rows); const companyGropsLoading = useAppSelector((state) => state.company_groups.loading); + const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup); async function getInitialData() { - if (!relatedGroupId) return; + if (!relatedGroupId) { + form.setFieldsValue({ + company_group_id: activeCompanyGroup?.id ?? undefined, + }); + return; + } setInitialDataLoading(true); try { const data = await fetchRelatedGroup(relatedGroupId); @@ -36,7 +42,7 @@ export const RelatedGroupForm: React.FC = ({ open, onCancel, onOk, relate form.setFieldsValue({ crm_id: data?.crm_id, name: data?.name, - created_date: data?.created_date ?? dayjs().format('YYYY-MM-DD'), + created_date: data?.created_date ?? null, company_group_id: data?.company_group_id, }); } catch (e) { @@ -53,7 +59,7 @@ export const RelatedGroupForm: React.FC = ({ open, onCancel, onOk, relate try { const { created_date, name, crm_id, company_group_id } = await form.validateFields(); await onOk({ - created_date: created_date ?? dayjs().format('YYYY-MM-DD'), + created_date: created_date ?? (relatedGroupId ? null : dayjs().format('YYYY-MM-DD')), name, crm_id, company_group_id: relatedGroupId ? undefined : company_group_id, @@ -61,6 +67,14 @@ export const RelatedGroupForm: React.FC = ({ open, onCancel, onOk, relate }); } catch (e) { if (e instanceof ApiError) { + if (e.code === 'CRM_ID_EXISTS') { + form.setFields([ + { + name: 'crm_id', + errors: [e.message], + }, + ]); + } notification.error({ description: e.message, }); @@ -96,7 +110,7 @@ export const RelatedGroupForm: React.FC = ({ open, onCancel, onOk, relate confirmLoading={confirmLoading}>
- + diff --git a/web/src/widgets/RelatedGroupTable/RelatedGroupTable.tsx b/web/src/widgets/RelatedGroupTable/RelatedGroupTable.tsx index e591330..f3a842a 100644 --- a/web/src/widgets/RelatedGroupTable/RelatedGroupTable.tsx +++ b/web/src/widgets/RelatedGroupTable/RelatedGroupTable.tsx @@ -62,17 +62,9 @@ export function RelatedGroupTable({ tabsComponent, data, loading, getData, activ } async function editRelatedGroupHandler(values: RelatedGroupFormType) { - try { - await editRelatedGroup(groupId, values); - getData(); - closeEditRelatedGroupHandler(); - } catch (e) { - if (e instanceof ApiError) { - notification.error({ - description: e.message, - }); - } - } + await editRelatedGroup(groupId, values); + getData(); + closeEditRelatedGroupHandler(); } const extraColumns: ColumnsType = useMemo( @@ -167,9 +159,7 @@ export function RelatedGroupTable({ tabsComponent, data, loading, getData, activ onCancel={() => { closeEditRelatedGroupHandler(); }} - onOk={async (values) => { - await editRelatedGroupHandler(values); - }} + onOk={editRelatedGroupHandler} /> )} {deleteModalOpen && ( diff --git a/web/src/widgets/RelatedGroupTable/config.tsx b/web/src/widgets/RelatedGroupTable/config.tsx index 34ebe25..fe4f8cb 100644 --- a/web/src/widgets/RelatedGroupTable/config.tsx +++ b/web/src/widgets/RelatedGroupTable/config.tsx @@ -6,13 +6,17 @@ import { store } from '../../store/store'; import type { RelatedGroupOut } from '../../types/api'; export const relateGroupConfig: TableConfig = { rowKey: 'id', - searchableKeys: ['code', 'name', 'members_count', 'created_date'], + searchableKeys: ['code', 'crm_id', 'name', 'members_count', 'created_date'], columns: [ { key: 'code', title: 'ID', features: { search: true, multiselect: true }, }, + { + key: 'crm_id', + title: 'ID в CRM', + }, { key: 'name', title: 'Наименование', @@ -35,7 +39,7 @@ export const relateGroupConfig: TableConfig = { key: 'created_date', title: 'Дата создания', render: (val) => { - return new Date(val as string).toLocaleDateString('ru-RU'); + return val ? new Date(val as string).toLocaleDateString('ru-RU') : '—'; }, }, ],