diff --git a/src/layouts/CatalogueGroups.tsx b/src/layouts/CatalogueGroups.tsx
index 3915a07..9a24e1e 100644
--- a/src/layouts/CatalogueGroups.tsx
+++ b/src/layouts/CatalogueGroups.tsx
@@ -1,3 +1,82 @@
+import { Button, Space } from "antd";
+import PageTitle from "../components/PageTitle";
+import { CatalogueJurTable } from "../widgets/CatalogueJurTable/CatalogueJurTable";
+import { PlusOutlined } from "@ant-design/icons";
+import { useState } from "react";
+import { useAppDispatch, useAppSelector } from "../store/store";
+import { CatalogueJurForm } from "../widgets/CatalogueJurForm/CatalogueJurForm";
+import { getCatalogueJurThunk } from "../store/slices/catalogueJurSlice/thunks";
+import { CatalogueJurFormProps } from "../types/catalogueJur/catalogueJur";
+import { createCatalogueJur } from "../services/api/directories/catalogue_jur";
+import { CompanyGroupsList } from "../widgets/CompanyGroupsList/CompanyGroupsList";
+
export function CatalogueGroup() {
- return
ГК и организации
;
+ const dispatch = useAppDispatch();
+ const isGettingArchive = useAppSelector(
+ (state) => state.catalogue_jur.isGettingArchive,
+ );
+
+ const [createFormOpen, setCreateFormOpen] = useState(false);
+
+ async function createJurHandler(values: CatalogueJurFormProps) {
+ try {
+ await createCatalogueJur(values);
+ dispatch(
+ getCatalogueJurThunk({ closed: isGettingArchive, outside_group: true }),
+ );
+ setCreateFormOpen(false);
+ } catch {}
+ }
+
+ return (
+
+
+
+ }
+ onClick={() => setCreateFormOpen(true)}
+ >
+ Создать ГК/ЮЛ
+
+
+
+ {createFormOpen && (
+
{
+ setCreateFormOpen(false);
+ }}
+ onOk={(values) => {
+ createJurHandler(values);
+ }}
+ />
+ )}
+
+ );
}
diff --git a/src/layouts/CatalogueJur.tsx b/src/layouts/CatalogueJur.tsx
index 018ebed..eaa9468 100644
--- a/src/layouts/CatalogueJur.tsx
+++ b/src/layouts/CatalogueJur.tsx
@@ -14,14 +14,14 @@ export function CatalogueJur() {
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: true }),
+ getCatalogueJurThunk({ closed: isGettingArchive, outside_group: outside_group }),
);
setCreateFormOpen(false);
} catch {}
@@ -46,17 +46,7 @@ export function CatalogueJur() {
Создать ЮЛ
-
-
-
+
{createFormOpen && (
{
- builder
- .addCase(getCompanyGroupsThunk.pending, (state) => {
- state.loading = true;
- state.error = null;
- })
- .addCase(getCompanyGroupsThunk.fulfilled, (state, action) => {
- state.raw_rows = action.payload;
- state.total_groups = action.payload.length;
- state.loading = false;
- })
- .addCase(getCompanyGroupsThunk.rejected, (state, action) => {
- state.error = action.payload ?? 'Неизвестная ошибка';
- state.loading = false;
- });
- },
+ name: "company_groups",
+ initialState,
+ reducers: {
+ setActiveCompanyGroup(state, action: PayloadAction) {
+ state.activeCompanyGroup = action.payload;
+ },
+ },
+ extraReducers: (builder) => {
+ builder
+ .addCase(getCompanyGroupsThunk.pending, (state) => {
+ state.loading = true;
+ state.error = null;
+ })
+ .addCase(getCompanyGroupsThunk.fulfilled, (state, action) => {
+ state.raw_rows = action.payload;
+ state.total_groups = action.payload.length;
+ state.loading = false;
+ })
+ .addCase(getCompanyGroupsThunk.rejected, (state, action) => {
+ state.error = action.payload ?? "Неизвестная ошибка";
+ state.loading = false;
+ });
+ },
});
-
+export const { setActiveCompanyGroup } = comGroupsSlice.actions;
export default comGroupsSlice.reducer;
diff --git a/src/store/slices/companyGroupsSlice/types.ts b/src/store/slices/companyGroupsSlice/types.ts
index 5f35cfa..aff3e9d 100644
--- a/src/store/slices/companyGroupsSlice/types.ts
+++ b/src/store/slices/companyGroupsSlice/types.ts
@@ -5,4 +5,5 @@ export interface CompanyGroupSliceType {
raw_rows: ICompanyGroup[];
loading: boolean;
error: string | null;
+ activeCompanyGroup?:ICompanyGroup | null
}
diff --git a/src/types/catalogueJur/catalogueJur.ts b/src/types/catalogueJur/catalogueJur.ts
index bbd6840..f291ab4 100644
--- a/src/types/catalogueJur/catalogueJur.ts
+++ b/src/types/catalogueJur/catalogueJur.ts
@@ -14,7 +14,7 @@ export interface ICatalogueJur {
updated_at: Date;
outside_group: boolean;
closed: boolean | string;
- memberships?: unknown[];
+ memberships?: MemberShips[];
aliases?: JurAlliase[];
regional_office: {
id: string;
@@ -23,6 +23,16 @@ export interface ICatalogueJur {
};
}
+export type KindType = "gsk" | "gsz"
+
+export type MemberShips = {
+ related_group_id: string;
+ code: string;
+ kind: KindType;
+ name: string;
+ valid_from: Date;
+};
+
export type JurAlliase = {
alias: string;
created_at: Date;
@@ -46,7 +56,9 @@ export type CatalogueJurFormProps = {
crm_id: string;
entity_type: "ЮЛ" | "ИП";
name: string;
- aliases?: string[] | {value:string, label:string}[];
+ aliases?: string[] | { value: string; label: string }[];
company_group_id?: string;
regional_office_id?: string;
+ gsk_id?: string;
+ gsz_id?: string;
};
diff --git a/src/widgets/CatalogueJurForm/CatalogueJurForm.tsx b/src/widgets/CatalogueJurForm/CatalogueJurForm.tsx
index 41ff66a..aa56376 100644
--- a/src/widgets/CatalogueJurForm/CatalogueJurForm.tsx
+++ b/src/widgets/CatalogueJurForm/CatalogueJurForm.tsx
@@ -1,12 +1,12 @@
-import React, { useCallback, useEffect, useState } from "react";
+import React, { useEffect, useState } from "react";
import { Modal, Form, Input, Select, Row, Col, InputNumber } from "antd";
import { CatalogueJurFormProps } from "../../types/catalogueJur/catalogueJur";
import { useAppDispatch, useAppSelector } from "../../store/store";
import { getCompanyGroupsThunk } from "../../store/slices/companyGroupsSlice/thunks";
-import { api } from "../../api/client";
-import { RegionalOffice } from "../../api/types";
-import { useAsyncData } from "../Admin/hooks";
import { fetchOneCatalogueJur } from "../../services/api/directories/catalogue_jur";
+import { fetchRelatedGroups } from "../../services/api/directories/company_groups";
+import { RelatedGroupOut } from "../../types/api";
+import { useMe } from "../../auth/useMe";
type Props = {
open: boolean;
@@ -23,34 +23,55 @@ export const CatalogueJurForm: React.FC = ({
}) => {
const [form] = Form.useForm();
const dispatch = useAppDispatch();
- const loadOffices = useCallback(
- () => api.get("/directories/regional-offices"),
- [],
- );
- const offices = useAsyncData(loadOffices);
- const type = Form.useWatch("entity_type", form);
+ const { me } = useMe();
- const { raw_rows, loading } = useAppSelector((state) => state.company_groups);
+ const type = Form.useWatch("entity_type", form);
+ const activeCompanyGroup = useAppSelector(
+ (state) => state.company_groups.activeCompanyGroup,
+ );
const [initialDataLoading, setInitialDataLoading] = useState(false);
+ const [gskData, setGskData] = useState([]);
+ const [gszData, setGszData] = useState([]);
+ const [loadingOptions, setLoadingOptions] = useState(false);
async function getInitialData() {
setInitialDataLoading(true);
+ form.setFieldsValue({
+ company_group_id: jurId ? undefined : activeCompanyGroup?.id,
+ regional_office_id: me?.regional_office.id,
+ });
if (jurId) {
const data = await fetchOneCatalogueJur(jurId);
form.setFieldsValue({
name: data?.name,
- company_group_id: data?.company_group_id,
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,
+ 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);
}
+ async function getRelatedGroupsHandler() {
+ if (activeCompanyGroup?.id) {
+ setLoadingOptions(true);
+ 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);
+ setLoadingOptions(false);
+ }
+ }
+
const handleOk = async () => {
try {
const values = await form.validateFields();
@@ -58,7 +79,6 @@ export const CatalogueJurForm: React.FC = ({
...values,
kpp: type === "ИП" ? undefined : values.kpp?.toString(),
inn: jurId ? undefined : values?.inn?.toString(),
- company_group_id: jurId ? undefined : values.company_group_id,
});
} catch {
return;
@@ -71,16 +91,19 @@ export const CatalogueJurForm: React.FC = ({
};
useEffect(() => {
- if (open && raw_rows.length === 0 && !loading) {
+ if (open) {
dispatch(getCompanyGroupsThunk());
}
- }, [open, raw_rows.length, loading, dispatch]);
+ }, [open, dispatch]);
useEffect(() => {
- if (!!jurId) {
- getInitialData();
- }
+ getInitialData();
}, [open]);
+
+ useEffect(() => {
+ getRelatedGroupsHandler();
+ }, [activeCompanyGroup]);
+
return (
= ({
-
+
-
+
diff --git a/src/widgets/CatalogueJurTable/CatalogueJurTable.tsx b/src/widgets/CatalogueJurTable/CatalogueJurTable.tsx
index 9df753c..bc56d1b 100644
--- a/src/widgets/CatalogueJurTable/CatalogueJurTable.tsx
+++ b/src/widgets/CatalogueJurTable/CatalogueJurTable.tsx
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from "react";
-import { Button, Checkbox, Dropdown, Input, Space } from "antd";
+import { Button, Checkbox, Dropdown, Input, Space, Tabs } from "antd";
import { useNavigate } from "react-router-dom";
import type { ColumnsType } from "antd/es/table";
import {
@@ -35,8 +35,17 @@ import {
import { WithdrawCatalogueJurForm } from "../WithdrawCatalogueJurForm/WithdrawCatalogueJurForm";
import { setIsGettingArchive } from "../../store/slices/catalogueJurSlice/catalogueJurSlice";
import { CatalogueJurForm } from "../CatalogueJurForm/CatalogueJurForm";
+import Title from "antd/es/typography/Title";
+import Text from "antd/es/typography/Text";
+import { fetchRelatedGroups } from "../../services/api/directories/company_groups";
+import { RelatedGroupOut } from "../../types/api";
-export function CatalogueJurTable() {
+interface CatalogueJurTableI {
+ outside_group: boolean;
+}
+type TabKey = "legal_entities" | "gsk" | "gsz";
+
+export function CatalogueJurTable({ outside_group }: CatalogueJurTableI) {
const navigate = useNavigate();
const dispatch = useAppDispatch();
const rawRows = useAppSelector((state) => state.catalogue_jur.raw_rows);
@@ -44,12 +53,18 @@ export function CatalogueJurTable() {
const isGettingArchive = useAppSelector(
(state) => state.catalogue_jur.isGettingArchive,
);
+ const activeCompanyGroup = useAppSelector(
+ (state) => state.company_groups.activeCompanyGroup,
+ );
const [moveCatalogueFormOpen, setMoveCatalogueFormOpen] = useState(false);
const [editCatalogueFormOpen, setEditCatalogueFormOpen] = useState(false);
const [withdrawCatalogueFormOpen, setWithdrawCatalogueFormOpen] =
useState(false);
+ const [activeTab, setActiveTab] = useState("legal_entities");
const [jurId, setJurId] = useState("");
+ const [gskData, setGskData] = useState([]);
+ const [gszData, setGszData] = useState([]);
const { visibleKeys, setVisibleKeys } = useVisibleColumns(catalogueJurConfig);
const {
rawQuery,
@@ -71,9 +86,12 @@ export function CatalogueJurTable() {
);
function getCatalogueJur() {
- // #TODO поменять на outside_group=true
dispatch(
- getCatalogueJurThunk({ closed: isGettingArchive, outside_group: true }),
+ getCatalogueJurThunk({
+ closed: isGettingArchive,
+ outside_group: outside_group,
+ company_group_id:activeCompanyGroup?.id
+ }),
);
}
@@ -117,13 +135,27 @@ export function CatalogueJurTable() {
dispatch(
getCatalogueJurThunk({ closed: isGettingArchive, outside_group: true }),
);
- closeEditCatalogueJurHandler()
+ closeEditCatalogueJurHandler();
} catch {}
}
+ async function getRelatedGroupsHandler() {
+ 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);
+ }
+ }
+
useEffect(() => {
getCatalogueJur();
- }, [isGettingArchive]);
+ }, [isGettingArchive, activeCompanyGroup]);
+
+ useEffect(() => {
+ getRelatedGroupsHandler();
+ }, [activeCompanyGroup]);
const extraColumns: ColumnsType = useMemo(
() => [
@@ -182,23 +214,62 @@ export function CatalogueJurTable() {
);
return (
-
+
+ {!outside_group && (
+
+
+ {activeCompanyGroup?.name}
+
+
+ {activeCompanyGroup?.base_regional_office_name ?? ""}
+ {activeCompanyGroup?.legal_entities_count} организаций
+
+
+ )}
- }
- placeholder="Поиск по ГК, CRM ID или РФ"
- value={rawQuery}
- onChange={(e) => setRawQuery(e.target.value)}
- style={{ maxWidth: 320 }}
- />
+ {outside_group ? (
+ }
+ placeholder="Поиск по ГК, CRM ID или РФ"
+ value={rawQuery}
+ onChange={(e) => setRawQuery(e.target.value)}
+ style={{ maxWidth: 320 }}
+ />
+ ) : (
+ setActiveTab(k as TabKey)}
+ style={{ marginBottom: 0 }}
+ items={[
+ {
+ key: "legal_entities",
+ label: `ЮЛ ${activeCompanyGroup?.legal_entities_count}`,
+ },
+ { key: "gsk", label: `ГСК ${gskData?.length ?? 0}` },
+ { key: "gsz", label: `ГСЗ ${gszData?.length ?? 0}` },
+ ]}
+ />
+ )}
+
{hasActiveFilters && (
-
{
- closeEditCatalogueJurHandler()
+ closeEditCatalogueJurHandler();
}}
onOk={(values) => {
editJurHandler(values);
diff --git a/src/widgets/CatalogueJurTable/config.tsx b/src/widgets/CatalogueJurTable/config.tsx
index 2920bc1..9aca89d 100644
--- a/src/widgets/CatalogueJurTable/config.tsx
+++ b/src/widgets/CatalogueJurTable/config.tsx
@@ -4,7 +4,7 @@ import { ICatalogueJur } from "../../types/catalogueJur/catalogueJur";
export const catalogueJurConfig: TableConfig = {
rowKey: "id",
- searchableKeys: ["closed", "inn", "kpp", "name", "company_group_name", "entity_type"],
+ searchableKeys: ["closed", "inn", "kpp", "name", "entity_type"],
columns: [
{
key: "closed",
@@ -30,11 +30,6 @@ export const catalogueJurConfig: TableConfig = {
title: "Организация",
features: { search: true, multiselect: true, sort: true },
},
- {
- key: "company_group_name",
- title: "ГК",
- features: { search: true, multiselect: true, sort: true },
- },
{
key: "entity_type",
title: "Тип",
diff --git a/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx b/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx
new file mode 100644
index 0000000..978153f
--- /dev/null
+++ b/src/widgets/CompanyGroupsList/CompanyGroupsList.tsx
@@ -0,0 +1,186 @@
+import { useEffect, useMemo, useState } from "react";
+import { Input, List, Spin, Empty, Typography, Tag } from "antd";
+import { FolderOpenOutlined, SearchOutlined } from "@ant-design/icons";
+import { useAppDispatch, useAppSelector } from "../../store/store";
+import { getCompanyGroupsThunk } from "../../store/slices/companyGroupsSlice/thunks";
+import { setActiveCompanyGroup } from "../../store/slices/companyGroupsSlice/companyGroupsSlice";
+
+const { Text } = Typography;
+
+export const CompanyGroupsList = () => {
+ const dispatch = useAppDispatch();
+
+ 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 [query, setQuery] = useState("");
+
+ const filtered = useMemo(() => {
+ const q = query.trim().toLowerCase();
+ if (!q) return rawRows;
+ return rawRows.filter(
+ (g) =>
+ g.name.toLowerCase().includes(q) || g.crm_id?.toLowerCase().includes(q),
+ );
+ }, [rawRows, query]);
+
+ useEffect(() => {
+ dispatch(getCompanyGroupsThunk());
+ }, [dispatch]);
+
+ useEffect(() => {
+ if (!activeCompanyGroup && rawRows?.length) {
+ dispatch(setActiveCompanyGroup(rawRows?.[0]));
+ }
+ }, [rawRows, activeCompanyGroup]);
+
+ return (
+
+
+ }
+ placeholder={"Поиск по ЮЛ или ГСК"}
+ value={query}
+ onChange={(e) => setQuery(e.target.value)}
+ />
+
+
+
+ {loading ? (
+
+
+
+ ) : filtered.length === 0 ? (
+
+ ) : (
+
{
+ const active = item.id === activeCompanyGroup?.id;
+ return (
+ dispatch(setActiveCompanyGroup(item))}
+ style={{
+ 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",
+ }}
+ onMouseEnter={(e) => {
+ if (!active) {
+ (e.currentTarget as HTMLElement).style.background =
+ "#fafafa";
+ }
+ }}
+ onMouseLeave={(e) => {
+ if (!active) {
+ (e.currentTarget as HTMLElement).style.background =
+ "transparent";
+ }
+ }}
+ >
+
+
+
+
+
+
+
+ {item.name}
+
+
+ CRM ID: {item.crm_id ?? "-"}
+
+
+
+
+ {item.legal_entities_count}
+
+
+
+ );
+ }}
+ />
+ )}
+
+
+ );
+};
diff --git a/src/widgets/CompanyGroupsTable/CompanyGroupsTable.tsx b/src/widgets/CompanyGroupsTable/CompanyGroupsTable.tsx
index a43905e..2faeb24 100644
--- a/src/widgets/CompanyGroupsTable/CompanyGroupsTable.tsx
+++ b/src/widgets/CompanyGroupsTable/CompanyGroupsTable.tsx
@@ -46,7 +46,7 @@ export function CompanyGroupsTable() {
);
return (
-