From c64975241be6271acf1cfb5e62152b95acba8856 Mon Sep 17 00:00:00 2001 From: Grog Date: Tue, 27 Oct 2026 17:04:18 +0300 Subject: [PATCH] =?UTF-8?q?aurora-(1636,=201693):=20=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BE=D1=87=D0=BD=D0=B8=D0=BA=D0=B0=20=D0=B3=D0=BA?= =?UTF-8?q?=20=D0=B8=20=D1=8E=D0=BB=20=D0=B8=20=D0=B8=D1=81=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=84=D0=B8=D0=BB=D1=8C?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D1=86=D0=B8=D1=8F=20=D1=8E=D0=BB=20=D0=B1?= =?UTF-8?q?=D0=B5=D0=B7=20=D0=B3=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/layouts/CatalogueGroups.tsx | 76 +++++++++++++++++-- .../api/directories/company_groups.ts | 22 +++++- .../companyGroupsSlice/companyGroupsSlice.ts | 11 ++- .../store/slices/companyGroupsSlice/thunks.ts | 9 ++- .../store/slices/companyGroupsSlice/types.ts | 5 ++ web/src/types/catalogueJur/catalogueJur.ts | 1 + web/src/types/companyGroups/companyGroups.ts | 3 +- .../ArchiveCompanyGroupModal.tsx | 26 +++++++ .../CatalogueGroupHeader.tsx | 73 ++++++++++++++---- .../CatalogueJurTable/CatalogueJurTable.tsx | 15 ++-- web/src/widgets/CatalogueJurTable/config.tsx | 28 ++++++- .../CompanyGroupForm/CompanyGroupForm.tsx | 42 +++++++--- .../CompanyGroupsList/CompanyGroupsList.tsx | 16 ++-- .../MoveCatalogueJurForm.tsx | 3 +- .../RelatedGroupForm/RelatedGroupForm.tsx | 4 +- .../RelatedGroupTable/RelatedGroupTable.tsx | 4 +- 16 files changed, 275 insertions(+), 63 deletions(-) create mode 100644 web/src/widgets/ArchiveCompanyGroupModal/ArchiveCompanyGroupModal.tsx diff --git a/web/src/layouts/CatalogueGroups.tsx b/web/src/layouts/CatalogueGroups.tsx index 6d712ea..94bf644 100644 --- a/web/src/layouts/CatalogueGroups.tsx +++ b/web/src/layouts/CatalogueGroups.tsx @@ -4,7 +4,13 @@ import { useEffect, useState } from 'react'; import { ApiError } from '../api/client'; import PageTitle from '../components/PageTitle'; import { createCatalogueJur } from '../services/api/directories/catalogue_jur'; -import { createCompanyGroup, fetchRelatedGroups } from '../services/api/directories/company_groups'; +import { + archiveCompanyGroup, + createCompanyGroup, + editCompanyGroup, + fetchRelatedGroups, + unarchiveCompanyGroup, +} 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'; @@ -12,7 +18,7 @@ import { getCompanyGroupsThunk } from '../store/slices/companyGroupsSlice/thunks import { useAppDispatch, useAppSelector } from '../store/store'; import type { RelatedGroupOut } from '../types/api'; import type { CatalogueJurFormProps } from '../types/catalogueJur/catalogueJur'; -import type { CreateCompanyGroupProps } from '../types/companyGroups/companyGroups'; +import type { CompanyGroupFormProps } from '../types/companyGroups/companyGroups'; import type { CreateEntityKind, RelatedGroupFormType } from '../types/relatedGroup/relatedGroup'; import { useNotificationApi } from '../utils/useNotification'; import { CataloguGroupTabs, type CatalogueGroupTabKey } from '../widgets/CataloguGroupTabs/CataloguGroupTabs'; @@ -24,6 +30,7 @@ import { CompanyGroupsList } from '../widgets/CompanyGroupsList/CompanyGroupsLis import { CreateEntityPickerModal } from '../widgets/CreateEntityPickerModal/CreateEntityPickerModal'; import { RelatedGroupForm } from '../widgets/RelatedGroupForm/RelatedGroupForm'; import { RelatedGroupTable } from '../widgets/RelatedGroupTable/RelatedGroupTable'; +import { ArchiveCompanyGroupModal } from '../widgets/ArchiveCompanyGroupModal/ArchiveCompanyGroupModal'; export function CatalogueGroup() { const dispatch = useAppDispatch(); @@ -34,16 +41,20 @@ export function CatalogueGroup() { const [entityCreateModalOpen, setEntityCreateModalOpen] = useState(false); const [kindForm, setKindForm] = useState(null); const [relatedGroupLoading, setRelatedGroupLoading] = useState(false); + const [companyGroupEditFormOpen, setCompanyGroupEditFormOpen] = useState(false); + const [companyGroupDeleteOpen, setCompanyGroupDeleteOpen] = useState(false); + const [companyGroupDeleteLoading, setCompanyGroupDeleteLoading] = useState(false); const [activeTab, setActiveTab] = useState('legal_entities'); const [gskData, setGskData] = useState([]); const [gszData, setGszData] = useState([]); 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); + const isGettingArchiveCompany = useAppSelector((state) => state.company_groups.isGettingArchive); async function createJurHandler(values: CatalogueJurFormProps) { await createCatalogueJur(values); - dispatch(getCompanyGroupsThunk()); + dispatch(getCompanyGroupsThunk({ is_archived: isGettingArchiveCompany })); dispatch( getCatalogueJurThunk({ closed: isGettingArchive, @@ -63,12 +74,43 @@ export function CatalogueGroup() { setKindForm(null); } } - async function createCompanyGroupHandler(values: CreateCompanyGroupProps) { + async function createCompanyGroupHandler(values: CompanyGroupFormProps) { await createCompanyGroup(values); - dispatch(getCompanyGroupsThunk()); - getRelatedGroupsHandler(); + dispatch(getCompanyGroupsThunk({ is_archived: isGettingArchiveCompany })); setKindForm(null); } + async function editCompanyGroupHandler(values: CompanyGroupFormProps) { + if (activeCompanyGroup?.id) { + await editCompanyGroup(activeCompanyGroup?.id, values); + dispatch(getCompanyGroupsThunk({ is_archived: isGettingArchiveCompany })); + setCompanyGroupEditFormOpen(false); + } + } + + async function archiveCompanyGroupHandler() { + if (!activeCompanyGroup) { + return; + } + try { + setCompanyGroupDeleteLoading(true); + if (activeCompanyGroup?.is_archived) { + await unarchiveCompanyGroup(activeCompanyGroup?.id); + } else { + await archiveCompanyGroup(activeCompanyGroup.id); + } + dispatch(getCompanyGroupsThunk({ is_archived: isGettingArchiveCompany })); + + setCompanyGroupDeleteOpen(false); + } catch (e) { + if (e instanceof ApiError) { + notification.error({ + description: e.message, + }); + } + } finally { + setCompanyGroupDeleteLoading(false); + } + } async function getRelatedGroupsHandler() { if (activeCompanyGroup?.id) { @@ -93,7 +135,6 @@ export function CatalogueGroup() { getRelatedGroupsHandler(); }, [activeCompanyGroup]); - // Без выбранной ГК таблица ЮЛ не грузится — выбираем первую ГК списка useEffect(() => { if (!activeCompanyGroup && rawRows?.length) { dispatch(setActiveCompanyGroup(rawRows[0])); @@ -140,7 +181,7 @@ export function CatalogueGroup() { flexDirection: 'column', overflow: 'hidden', }}> - + {activeTab === 'legal_entities' && ( )} + {companyGroupEditFormOpen && ( + { + setCompanyGroupEditFormOpen(false); + }} + onOk={editCompanyGroupHandler} + companyGroupId={activeCompanyGroup?.id} + /> + )} + {companyGroupDeleteOpen && activeCompanyGroup && ( + setCompanyGroupDeleteOpen(false)} + onOk={archiveCompanyGroupHandler} + isArchived={activeCompanyGroup?.is_archived} + /> + )} ); } diff --git a/web/src/services/api/directories/company_groups.ts b/web/src/services/api/directories/company_groups.ts index 9ca3f26..75df33c 100644 --- a/web/src/services/api/directories/company_groups.ts +++ b/web/src/services/api/directories/company_groups.ts @@ -1,15 +1,20 @@ import { api } from '../../../api/client'; +import { GetCompanyGroupsPropsI } from '../../../store/slices/companyGroupsSlice/types'; import type { LegalEntityBrief, Page, RelatedGroupDetail, RelatedGroupOut } from '../../../types/api'; -import type { CreateCompanyGroupProps, ICompanyGroupOut } from '../../../types/companyGroups/companyGroups'; +import type { CompanyGroupFormProps, ICompanyGroupOut } from '../../../types/companyGroups/companyGroups'; const CG_PAGE = 200; export const LE_PAGE = 200; /** Все видимые ГК — дочитываем страницы, пока не получим total. */ -export async function fetchCompanyGroups(): Promise { +export async function fetchCompanyGroups(params: GetCompanyGroupsPropsI): Promise { const all: ICompanyGroupOut[] = []; for (let offset = 0; ; offset += CG_PAGE) { - const page = await api.get>(`/directories/company-groups?limit=${CG_PAGE}&offset=${offset}`); + const page = await api.get>(`/directories/company-groups`, { + limit: CG_PAGE, + offset: offset, + ...params, + }); all.push(...page.items); if (all.length >= page.total || page.items.length === 0) { return all; @@ -37,6 +42,15 @@ export async function fetchAllLegalEntities(groupId: string): Promise api.get(`/directories/legal-entities/${id}`); -export function createCompanyGroup(body: CreateCompanyGroupProps): Promise { +export function createCompanyGroup(body: CompanyGroupFormProps): Promise { return api.post('/directories/company-groups', body); } +export function editCompanyGroup(id: string, body: CompanyGroupFormProps): Promise { + return api.patch(`/directories/company-groups/${id}`, body); +} +export function archiveCompanyGroup(id: string): Promise { + return api.post(`/directories/company-groups/${id}/archive`); +} +export function unarchiveCompanyGroup(id: string): Promise { + return api.post(`/directories/company-groups/${id}/unarchive`); +} diff --git a/web/src/store/slices/companyGroupsSlice/companyGroupsSlice.ts b/web/src/store/slices/companyGroupsSlice/companyGroupsSlice.ts index c56a483..0529e70 100644 --- a/web/src/store/slices/companyGroupsSlice/companyGroupsSlice.ts +++ b/web/src/store/slices/companyGroupsSlice/companyGroupsSlice.ts @@ -1,4 +1,4 @@ -import { createSlice } from '@reduxjs/toolkit'; +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { getCompanyGroupsThunk } from './thunks'; import type { CompanyGroupSliceType } from './types'; @@ -6,13 +6,18 @@ const initialState: CompanyGroupSliceType = { raw_rows: [], total_groups: 0, loading: false, + isGettingArchive: false, error: null, }; const comGroupsSlice = createSlice({ name: 'company_groups', initialState, - reducers: {}, + reducers: { + setIsGettingArchive(state, action: PayloadAction) { + state.isGettingArchive = action.payload; + }, + }, extraReducers: (builder) => { builder .addCase(getCompanyGroupsThunk.pending, (state) => { @@ -30,4 +35,6 @@ const comGroupsSlice = createSlice({ }); }, }); +export const { setIsGettingArchive } = comGroupsSlice.actions; + export default comGroupsSlice.reducer; diff --git a/web/src/store/slices/companyGroupsSlice/thunks.ts b/web/src/store/slices/companyGroupsSlice/thunks.ts index df8c904..042e5e0 100644 --- a/web/src/store/slices/companyGroupsSlice/thunks.ts +++ b/web/src/store/slices/companyGroupsSlice/thunks.ts @@ -1,14 +1,15 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; import { fetchCompanyGroups } from '../../../services/api/directories/company_groups'; import { type ICompanyGroup, toCompanyGroupRow } from '../../../types/companyGroups/companyGroups'; +import { GetCompanyGroupsPropsI } from './types'; -export const getCompanyGroupsThunk = createAsyncThunk( +export const getCompanyGroupsThunk = createAsyncThunk( 'company_groups/getAll', - async (_, thunkApi) => { + async (args = {}, thunkApi) => { try { - return (await fetchCompanyGroups()).map(toCompanyGroupRow); + return (await fetchCompanyGroups(args)).map(toCompanyGroupRow); } catch (e) { return thunkApi.rejectWithValue(e instanceof Error ? e.message : 'Ошибка'); } }, -); +) diff --git a/web/src/store/slices/companyGroupsSlice/types.ts b/web/src/store/slices/companyGroupsSlice/types.ts index 5f35cfa..fcbd521 100644 --- a/web/src/store/slices/companyGroupsSlice/types.ts +++ b/web/src/store/slices/companyGroupsSlice/types.ts @@ -5,4 +5,9 @@ export interface CompanyGroupSliceType { raw_rows: ICompanyGroup[]; loading: boolean; error: string | null; + isGettingArchive: boolean; +} + +export interface GetCompanyGroupsPropsI { + is_archived?: boolean; } diff --git a/web/src/types/catalogueJur/catalogueJur.ts b/web/src/types/catalogueJur/catalogueJur.ts index 5d6e472..68369bb 100644 --- a/web/src/types/catalogueJur/catalogueJur.ts +++ b/web/src/types/catalogueJur/catalogueJur.ts @@ -21,6 +21,7 @@ export interface ICatalogueJur { name: string; is_head_office: boolean; }; + regional_name?:string; } export type KindType = 'gsk' | 'gsz'; diff --git a/web/src/types/companyGroups/companyGroups.ts b/web/src/types/companyGroups/companyGroups.ts index 8909640..9b7bed3 100644 --- a/web/src/types/companyGroups/companyGroups.ts +++ b/web/src/types/companyGroups/companyGroups.ts @@ -6,6 +6,7 @@ export interface ICompanyGroupOut { base_regional_office_id: string | null; base_regional_office: { id: string; name: string; is_head_office: boolean } | null; legal_entities_count: number; + is_archived:boolean; } /** Строка таблицы ГК: имя филиала плоским полем — по нему работают поиск и фильтры GenericTable. */ @@ -18,7 +19,7 @@ export const toCompanyGroupRow = (g: ICompanyGroupOut): ICompanyGroup => ({ base_regional_office_name: g.base_regional_office?.name ?? '—', }); -export interface CreateCompanyGroupProps { +export interface CompanyGroupFormProps { name: string; crm_id: string; base_regional_office_id: string | null; diff --git a/web/src/widgets/ArchiveCompanyGroupModal/ArchiveCompanyGroupModal.tsx b/web/src/widgets/ArchiveCompanyGroupModal/ArchiveCompanyGroupModal.tsx new file mode 100644 index 0000000..150f608 --- /dev/null +++ b/web/src/widgets/ArchiveCompanyGroupModal/ArchiveCompanyGroupModal.tsx @@ -0,0 +1,26 @@ +import { Modal } from 'antd'; + +type Props = { + open: boolean; + onCancel: () => void; + onOk: () => void | Promise; + loading?: boolean; + isArchived: boolean; +}; + +export const ArchiveCompanyGroupModal: React.FC = ({ open, onCancel, onOk, loading, isArchived }) => { + return ( + +

Группа компании будет {isArchived ? 'разархивированна' : 'архивированна'}

+
+ ); +}; diff --git a/web/src/widgets/CatalogueGroupHeader/CatalogueGroupHeader.tsx b/web/src/widgets/CatalogueGroupHeader/CatalogueGroupHeader.tsx index 1b5deb2..c1e6eb3 100644 --- a/web/src/widgets/CatalogueGroupHeader/CatalogueGroupHeader.tsx +++ b/web/src/widgets/CatalogueGroupHeader/CatalogueGroupHeader.tsx @@ -1,33 +1,74 @@ -import { Space } from 'antd'; +import { Button, Dropdown, Space } from 'antd'; import Text from 'antd/es/typography/Text'; import Title from 'antd/es/typography/Title'; import { useAppSelector } from '../../store/store'; import { pluralRu } from '../../utils/labels'; +import { DeleteOutlined, EditOutlined, EllipsisOutlined, HistoryOutlined } from '@ant-design/icons'; +import { useNavigate } from 'react-router-dom'; -export const CompanyGroupHeader = () => { +interface CompanyGroupHeaderI { + setDeleteConfirmOpen: (el: boolean) => void; + setEditFormOpen: (el: boolean) => void; +} + +export const CompanyGroupHeader = ({ setEditFormOpen, setDeleteConfirmOpen }: CompanyGroupHeaderI) => { const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup); const count = activeCompanyGroup?.legal_entities_count ?? 0; - + const navigate = useNavigate(); const organizationWord = pluralRu(count, ['организация', 'организации', 'организаций']); + const items = [ + { + key: 'edit', + icon: , + label: 'Изменить ГК', + onClick: () => { + setEditFormOpen(true); + }, + }, + { + key: 'history', + icon: , + label: 'История изменений', + onClick: () => navigate('/logging'), + }, + { + key: 'delete', + icon: , + label: activeCompanyGroup?.is_archived ? 'Разархивировать' : 'Архивировать', + danger: true, + onClick: () => { + setDeleteConfirmOpen(true); + }, + }, + ]; + return ( -
- - {activeCompanyGroup?.name ?? ''} - - - - {activeCompanyGroup?.base_regional_office_name ?? ''} - - - {count ?? 0} {organizationWord} - - -
+
+ + {activeCompanyGroup?.name ?? ''} + + + + {activeCompanyGroup?.base_regional_office_name ?? ''} + + + {count ?? 0} {organizationWord} + + +
+ + + + ); }; diff --git a/web/src/widgets/CatalogueJurTable/CatalogueJurTable.tsx b/web/src/widgets/CatalogueJurTable/CatalogueJurTable.tsx index 94c3112..52af6cf 100644 --- a/web/src/widgets/CatalogueJurTable/CatalogueJurTable.tsx +++ b/web/src/widgets/CatalogueJurTable/CatalogueJurTable.tsx @@ -52,14 +52,16 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur const [editCatalogueFormOpen, setEditCatalogueFormOpen] = useState(false); const [withdrawCatalogueFormOpen, setWithdrawCatalogueFormOpen] = useState(false); const [jurId, setJurId] = useState(''); + const isGettingArchiveCompany = useAppSelector((state) => state.company_groups.isGettingArchive); const filterdData = useMemo(() => { + let newData = rawRows if (relatedGroupFilter?.id && !outside_group) { - return rawRows?.filter((row) => { + newData = rawRows?.filter((row) => { return row?.memberships?.some((member) => member.related_group_id === relatedGroupFilter.id); }); } - return rawRows; + return newData?.map((elem) => elem && { ...elem, regional_name: elem?.regional_office?.name }); }, [rawRows, relatedGroupFilter, outside_group]); const { visibleKeys, setVisibleKeys } = useVisibleColumns(catalogueJurConfig); @@ -67,7 +69,7 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur useTableFilters(); // single filtered array — title count and table share it const { rows } = useFilteredRows(filterdData, catalogueJurConfig, rawQuery, columnFilters, sort); - + function getCatalogueJur() { dispatch( getCatalogueJurThunk({ @@ -95,7 +97,7 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur try { await moveCatalogueJur(jurId, values); getCatalogueJur(); - dispatch(getCompanyGroupsThunk()); + dispatch(getCompanyGroupsThunk({ is_archived: isGettingArchiveCompany })); closeMoveCatalogueJurHandler(); } catch (e) { if (e instanceof ApiError) { @@ -109,7 +111,7 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur try { await withdrawCatalogueJur(jurId, values); getCatalogueJur(); - dispatch(getCompanyGroupsThunk()); + dispatch(getCompanyGroupsThunk({ is_archived: isGettingArchiveCompany })); closeWithdrawCatalogueJurHandler(); } catch (e) { @@ -128,7 +130,6 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur } useEffect(() => { - // «ЮЛ вне ГК» грузится без выбранной ГК; список ГК — только по выбранной (без неё запрос ушёл бы по всем ГК) if (outside_group || activeCompanyGroup?.id) { getCatalogueJur(); } @@ -244,7 +245,7 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur justifyContent: 'space-between', gap: 16, padding: '10px 16px', - background: '#fff8e1', // светло-жёлтый фон + background: '#fff8e1', borderTop: '1px solid #ffe58f', borderBottom: '1px solid #ffe58f', borderRadius: 8, diff --git a/web/src/widgets/CatalogueJurTable/config.tsx b/web/src/widgets/CatalogueJurTable/config.tsx index 48e3dc8..4edc4bf 100644 --- a/web/src/widgets/CatalogueJurTable/config.tsx +++ b/web/src/widgets/CatalogueJurTable/config.tsx @@ -5,7 +5,7 @@ import type { ICatalogueJur } from '../../types/catalogueJur/catalogueJur'; export const catalogueJurConfig: TableConfig = { rowKey: 'id', - searchableKeys: ['closed', 'inn', 'kpp', 'name', 'entity_type'], + searchableKeys: ['closed', 'inn', 'crm_id', 'kpp', 'name', 'entity_type', 'regional_name'], columns: [ { key: 'closed', @@ -18,6 +18,28 @@ export const catalogueJurConfig: TableConfig = { return ; }, }, + { + key: 'crm_id', + title: 'Входит в ГСК', + render: (_: unknown, row) => { + const has = row?.memberships?.some((elem) => elem.kind === 'gsk'); + const preset = has ? TAG_PRESETS.green : TAG_PRESETS.gray; + const text = has ? 'Входит' : 'Не входит'; + + return ; + }, + }, + { + key: 'company_group_id', + title: 'Входит в ГСЗ', + render: (_: unknown, row) => { + const has = row?.memberships?.some((elem) => elem.kind === 'gsz'); + const preset = has ? TAG_PRESETS.green : TAG_PRESETS.gray; + const text = has ? 'Входит' : 'Не входит'; + + return ; + }, + }, { key: 'inn', title: 'ИНН', @@ -43,9 +65,9 @@ export const catalogueJurConfig: TableConfig = { }, }, { - key: 'regional_office', + key: 'regional_name', title: 'Основной РФ', - render: (val) => (val as ICatalogueJur['regional_office'] | null)?.name, + features: { search: true, multiselect: true, sort: true }, }, ], }; diff --git a/web/src/widgets/CompanyGroupForm/CompanyGroupForm.tsx b/web/src/widgets/CompanyGroupForm/CompanyGroupForm.tsx index 76e31f6..b25529f 100644 --- a/web/src/widgets/CompanyGroupForm/CompanyGroupForm.tsx +++ b/web/src/widgets/CompanyGroupForm/CompanyGroupForm.tsx @@ -3,26 +3,47 @@ import type React from 'react'; import { useEffect, useState } from 'react'; import { ApiError } from '../../api/client'; import { useMe } from '../../auth/useMe'; -import { useAppSelector } from '../../store/store'; -import type { CreateCompanyGroupProps } from '../../types/companyGroups/companyGroups'; +import type { CompanyGroupFormProps } from '../../types/companyGroups/companyGroups'; import { useNotificationApi } from '../../utils/useNotification'; import { loadOffices } from '../Admin/UsersTable'; +import { fetchOneCompanyGroup } from '../../services/api/directories/company_groups'; type Props = { open: boolean; onCancel: () => void; - onOk: (values: CreateCompanyGroupProps) => void | Promise; + onOk: (values: CompanyGroupFormProps) => void | Promise; + companyGroupId?: string; }; -export const CompanyGroupForm: React.FC = ({ open, onCancel, onOk }) => { - const [form] = Form.useForm(); +export const CompanyGroupForm: React.FC = ({ open, onCancel, onOk, companyGroupId }) => { + const [form] = Form.useForm(); const { me } = useMe(); const notification = useNotificationApi(); - const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup); const [officesOptions, setOfficesOptions] = useState<{ value: string; label: string }[]>([]); const [loadingOptions, setLoadingOptions] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false); + const [initialDataLoading, setInitialDataLoading] = useState(false); + + async function getInitialData() { + if (companyGroupId) { + setInitialDataLoading(true); + try { + const data = await fetchOneCompanyGroup(companyGroupId); + form.setFieldsValue({ + name: data.name, + crm_id: data.crm_id ?? undefined, + base_regional_office_id: data.base_regional_office_id, + }); + } catch (e) { + if (e instanceof ApiError) { + notification.error({ description: e.message }); + } + } finally { + setInitialDataLoading(false); + } + } + } async function getOfficesOptionsHandler() { setLoadingOptions(true); @@ -45,6 +66,7 @@ export const CompanyGroupForm: React.FC = ({ open, onCancel, onOk }) => { const values = await form.validateFields(); await onOk({ ...values, + crm_id: values?.crm_id ?? null, base_regional_office_id: values?.base_regional_office_id ? values?.base_regional_office_id : (me?.regional_office.id as string), }); } catch (e) { @@ -72,18 +94,20 @@ export const CompanyGroupForm: React.FC = ({ open, onCancel, onOk }) => { }; useEffect(() => { + getInitialData(); getOfficesOptionsHandler(); - }, [activeCompanyGroup]); + }, []); return (
diff --git a/web/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx b/web/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx index 47d0caf..c723ad1 100644 --- a/web/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx +++ b/web/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx @@ -1,10 +1,11 @@ import { FolderOpenOutlined, SearchOutlined } from '@ant-design/icons'; -import { Empty, Input, List, Spin, Tag, Typography } from 'antd'; +import { Checkbox, Empty, Input, List, Space, Spin, Tag, Typography } from 'antd'; import { useEffect, useMemo, useState } from 'react'; import { useVirtualList } from '../../hooks/useVirtualList'; import { setActiveCompanyGroup } from '../../store/slices/catalogueJurSlice/catalogueJurSlice'; import { getCompanyGroupsThunk } from '../../store/slices/companyGroupsSlice/thunks'; import { useAppDispatch, useAppSelector } from '../../store/store'; +import { setIsGettingArchive } from '../../store/slices/companyGroupsSlice/companyGroupsSlice'; const { Text } = Typography; @@ -14,7 +15,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.catalogue_jur.activeCompanyGroup); - + const isGettingArchiveCompany = useAppSelector((state) => state.company_groups.isGettingArchive); const [query, setQuery] = useState(''); const filtered = useMemo(() => { @@ -30,8 +31,8 @@ export const CompanyGroupsList = () => { }); useEffect(() => { - dispatch(getCompanyGroupsThunk()); - }, [dispatch]); + dispatch(getCompanyGroupsThunk({is_archived:isGettingArchiveCompany})); + }, [dispatch, isGettingArchiveCompany]); useEffect(() => { if (!activeCompanyGroup && rawRows?.length) { @@ -57,7 +58,7 @@ export const CompanyGroupsList = () => { borderRight: '1px solid #f0f0f0', borderRadius: 12, }}> -
+ } @@ -65,7 +66,10 @@ export const CompanyGroupsList = () => { value={query} onChange={(e) => setQuery(e.target.value)} /> -
+ dispatch(setIsGettingArchive(e.target.checked))}> + Архив + +
{filtered.length === 0 ? ( diff --git a/web/src/widgets/MoveCatalogueJurForm/MoveCatalogueJurForm.tsx b/web/src/widgets/MoveCatalogueJurForm/MoveCatalogueJurForm.tsx index 61ed5c5..4e68770 100644 --- a/web/src/widgets/MoveCatalogueJurForm/MoveCatalogueJurForm.tsx +++ b/web/src/widgets/MoveCatalogueJurForm/MoveCatalogueJurForm.tsx @@ -29,6 +29,7 @@ export const MoveCatalogueJurForm: React.FC = ({ open, onCancel, onOk, ju const [form] = Form.useForm(); const dispatch = useAppDispatch(); const notification = useNotificationApi(); + const isGettingArchiveCompany = useAppSelector((state) => state.company_groups.isGettingArchive); const { raw_rows, loading } = useAppSelector((state) => state.company_groups); const [initialDataLoading, setInitialDataLoading] = useState(false); @@ -76,7 +77,7 @@ export const MoveCatalogueJurForm: React.FC = ({ open, onCancel, onOk, ju }; useEffect(() => { if (open && raw_rows.length === 0 && !loading) { - dispatch(getCompanyGroupsThunk()); + dispatch(getCompanyGroupsThunk({ is_archived: isGettingArchiveCompany })); } }, [open, raw_rows.length, loading, dispatch]); diff --git a/web/src/widgets/RelatedGroupForm/RelatedGroupForm.tsx b/web/src/widgets/RelatedGroupForm/RelatedGroupForm.tsx index d4ed42e..b60cfea 100644 --- a/web/src/widgets/RelatedGroupForm/RelatedGroupForm.tsx +++ b/web/src/widgets/RelatedGroupForm/RelatedGroupForm.tsx @@ -27,6 +27,7 @@ export const RelatedGroupForm: React.FC = ({ open, onCancel, onOk, relate 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 isGettingArchiveCompany = useAppSelector((state) => state.company_groups.isGettingArchive); async function getInitialData() { if (!relatedGroupId) { @@ -38,7 +39,8 @@ export const RelatedGroupForm: React.FC = ({ open, onCancel, onOk, relate setInitialDataLoading(true); try { const data = await fetchRelatedGroup(relatedGroupId); - await dispatch(getCompanyGroupsThunk()); + await dispatch(getCompanyGroupsThunk({ is_archived: isGettingArchiveCompany })); + form.setFieldsValue({ crm_id: data?.crm_id, name: data?.name, diff --git a/web/src/widgets/RelatedGroupTable/RelatedGroupTable.tsx b/web/src/widgets/RelatedGroupTable/RelatedGroupTable.tsx index f3a842a..d5819a4 100644 --- a/web/src/widgets/RelatedGroupTable/RelatedGroupTable.tsx +++ b/web/src/widgets/RelatedGroupTable/RelatedGroupTable.tsx @@ -1,4 +1,4 @@ -import { EllipsisOutlined } from '@ant-design/icons'; +import { DeleteOutlined, EditOutlined, EllipsisOutlined } from '@ant-design/icons'; import { Button, Dropdown, Space } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { type ReactNode, useMemo, useState } from 'react'; @@ -77,6 +77,7 @@ export function RelatedGroupTable({ tabsComponent, data, loading, getData, activ const items = [ { key: 'edit', + icon: , label: 'Изменить', onClick: () => { setGroupId(row.id); @@ -85,6 +86,7 @@ export function RelatedGroupTable({ tabsComponent, data, loading, getData, activ }, { key: 'delete', + icon: , label: 'Удалить', danger: true, onClick: () => {