added company group table #31
@ -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 <h3>ГК и организации</h3>;
|
||||
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 (
|
||||
<div
|
||||
style={{
|
||||
padding: 12,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "100vh",
|
||||
}}
|
||||
>
|
||||
<Space style={{ justifyContent: "space-between" }}>
|
||||
<PageTitle
|
||||
header="Группы компаний и организаций"
|
||||
location="Справочники"
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => setCreateFormOpen(true)}
|
||||
>
|
||||
Создать ГК/ЮЛ
|
||||
</Button>
|
||||
</Space>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
display: "flex",
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
<div style={{ width: 320, flexShrink: 0, minHeight: 0 }}>
|
||||
<CompanyGroupsList/>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: 1, minWidth: 0, minHeight: 0, borderRadius:12, background:'white' }}>
|
||||
<CatalogueJurTable outside_group={false} />
|
||||
</div>
|
||||
</div>
|
||||
{createFormOpen && (
|
||||
<CatalogueJurForm
|
||||
open={createFormOpen}
|
||||
onCancel={() => {
|
||||
setCreateFormOpen(false);
|
||||
}}
|
||||
onOk={(values) => {
|
||||
createJurHandler(values);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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() {
|
||||
Создать ЮЛ
|
||||
</Button>
|
||||
</Space>
|
||||
<main
|
||||
style={{
|
||||
flex: "1 1 auto",
|
||||
minHeight: 0,
|
||||
overflow: "auto",
|
||||
backgroundColor: "white",
|
||||
borderRadius: 12,
|
||||
}}
|
||||
>
|
||||
<CatalogueJurTable />
|
||||
</main>
|
||||
<CatalogueJurTable outside_group={outside_group}/>
|
||||
{createFormOpen && (
|
||||
<CatalogueJurForm
|
||||
open={createFormOpen}
|
||||
|
||||
@ -12,4 +12,5 @@ export interface CatalogueJurSliceType{
|
||||
export interface GetCatalogueJurPropsI{
|
||||
closed?:boolean
|
||||
outside_group?:boolean
|
||||
company_group_id?:string
|
||||
}
|
||||
|
||||
@ -1,34 +1,40 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { getCompanyGroupsThunk } from './thunks';
|
||||
import type { CompanyGroupSliceType } from './types';
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { getCompanyGroupsThunk } from "./thunks";
|
||||
import type { CompanyGroupSliceType } from "./types";
|
||||
import { ICompanyGroup } from "../../../types/companyGroups/companyGroups";
|
||||
|
||||
const initialState: CompanyGroupSliceType = {
|
||||
raw_rows: [],
|
||||
total_groups: 0,
|
||||
loading: false,
|
||||
error: null,
|
||||
raw_rows: [],
|
||||
total_groups: 0,
|
||||
loading: false,
|
||||
error: null,
|
||||
activeCompanyGroup: null,
|
||||
};
|
||||
|
||||
const comGroupsSlice = createSlice({
|
||||
name: 'company_groups',
|
||||
initialState,
|
||||
reducers: {},
|
||||
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;
|
||||
});
|
||||
},
|
||||
name: "company_groups",
|
||||
initialState,
|
||||
reducers: {
|
||||
setActiveCompanyGroup(state, action: PayloadAction<ICompanyGroup | null>) {
|
||||
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;
|
||||
|
||||
@ -5,4 +5,5 @@ export interface CompanyGroupSliceType {
|
||||
raw_rows: ICompanyGroup[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
activeCompanyGroup?:ICompanyGroup | null
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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<Props> = ({
|
||||
}) => {
|
||||
const [form] = Form.useForm<CatalogueJurFormProps>();
|
||||
const dispatch = useAppDispatch();
|
||||
const loadOffices = useCallback(
|
||||
() => api.get<RegionalOffice[]>("/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<RelatedGroupOut[]>([]);
|
||||
const [gszData, setGszData] = useState<RelatedGroupOut[]>([]);
|
||||
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<Props> = ({
|
||||
...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<Props> = ({
|
||||
};
|
||||
|
||||
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 (
|
||||
<Modal
|
||||
title={
|
||||
@ -183,30 +206,29 @@ export const CatalogueJurForm: React.FC<Props> = ({
|
||||
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Form.Item name="company_group_id" label="Входит в ГСК">
|
||||
<Form.Item name="gsk_id" label="Входит в ГСК">
|
||||
<Select
|
||||
disabled={!!jurId}
|
||||
allowClear
|
||||
placeholder="— не указан —"
|
||||
options={raw_rows?.map((g) => ({ value: g.id, label: g.name }))}
|
||||
options={gskData?.map((g) => ({ value: g.id, label: g.name }))}
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
notFoundContent={loading ? "Загрузка" : "Нет вариантов"}
|
||||
notFoundContent={loadingOptions ? "Загрузка" : "Нет вариантов"}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item name="regional_office_id" label="Входит в ГСЗ">
|
||||
<Form.Item name="gsz_id" label="Входит в ГСЗ">
|
||||
<Select
|
||||
allowClear
|
||||
placeholder="— не указан —"
|
||||
options={offices?.data?.map((g) => ({
|
||||
options={gszData?.map((g) => ({
|
||||
value: g.id,
|
||||
label: g.name,
|
||||
}))}
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
notFoundContent={loading ? "Загрузка" : "Нет вариантов"}
|
||||
notFoundContent={loadingOptions ? "Загрузка" : "Нет вариантов"}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
@ -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<TabKey>("legal_entities");
|
||||
const [jurId, setJurId] = useState("");
|
||||
const [gskData, setGskData] = useState<RelatedGroupOut[]>([]);
|
||||
const [gszData, setGszData] = useState<RelatedGroupOut[]>([]);
|
||||
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<ICatalogueJur> = useMemo(
|
||||
() => [
|
||||
@ -182,23 +214,62 @@ export function CatalogueJurTable() {
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
background: "white",
|
||||
borderRadius: 12,
|
||||
}}
|
||||
>
|
||||
{!outside_group && (
|
||||
<div
|
||||
style={{ padding: "12px 16px", borderBottom: "1px solid #0f172a0f" }}
|
||||
>
|
||||
<Title level={5} style={{ margin: 0 }}>
|
||||
{activeCompanyGroup?.name}
|
||||
</Title>
|
||||
<Text type="secondary" style={{ fontSize: 13 }}>
|
||||
{activeCompanyGroup?.base_regional_office_name ?? ""}
|
||||
{activeCompanyGroup?.legal_entities_count} организаций
|
||||
</Text>
|
||||
</div>
|
||||
)}
|
||||
<Space
|
||||
style={{
|
||||
padding: "16px 12px",
|
||||
padding: "0 12px",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
borderBottom: "1px",
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
allowClear
|
||||
prefix={<SearchOutlined />}
|
||||
placeholder="Поиск по ГК, CRM ID или РФ"
|
||||
value={rawQuery}
|
||||
onChange={(e) => setRawQuery(e.target.value)}
|
||||
style={{ maxWidth: 320 }}
|
||||
/>
|
||||
{outside_group ? (
|
||||
<Input
|
||||
allowClear
|
||||
prefix={<SearchOutlined />}
|
||||
placeholder="Поиск по ГК, CRM ID или РФ"
|
||||
value={rawQuery}
|
||||
onChange={(e) => setRawQuery(e.target.value)}
|
||||
style={{ maxWidth: 320 }}
|
||||
/>
|
||||
) : (
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
onChange={(k) => 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}` },
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Space>
|
||||
{hasActiveFilters && (
|
||||
<Button
|
||||
@ -210,13 +281,14 @@ export function CatalogueJurTable() {
|
||||
Сбросить фильтры
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Checkbox
|
||||
checked={isGettingArchive}
|
||||
onChange={(e) => dispatch(setIsGettingArchive(e.target.checked))}
|
||||
>
|
||||
Архив
|
||||
</Checkbox>
|
||||
{activeTab === "legal_entities" && (
|
||||
<Checkbox
|
||||
checked={isGettingArchive}
|
||||
onChange={(e) => dispatch(setIsGettingArchive(e.target.checked))}
|
||||
>
|
||||
Архив
|
||||
</Checkbox>
|
||||
)}
|
||||
<ColumnSettings
|
||||
defs={catalogueJurConfig.columns}
|
||||
visibleKeys={visibleKeys}
|
||||
@ -224,7 +296,6 @@ export function CatalogueJurTable() {
|
||||
/>
|
||||
</Space>
|
||||
</Space>
|
||||
|
||||
<DataTable
|
||||
sortState={sort}
|
||||
onSortChange={setSort}
|
||||
@ -267,7 +338,7 @@ export function CatalogueJurTable() {
|
||||
jurId={jurId}
|
||||
open={editCatalogueFormOpen}
|
||||
onCancel={() => {
|
||||
closeEditCatalogueJurHandler()
|
||||
closeEditCatalogueJurHandler();
|
||||
}}
|
||||
onOk={(values) => {
|
||||
editJurHandler(values);
|
||||
|
||||
@ -4,7 +4,7 @@ import { ICatalogueJur } from "../../types/catalogueJur/catalogueJur";
|
||||
|
||||
export const catalogueJurConfig: TableConfig<ICatalogueJur> = {
|
||||
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<ICatalogueJur> = {
|
||||
title: "Организация",
|
||||
features: { search: true, multiselect: true, sort: true },
|
||||
},
|
||||
{
|
||||
key: "company_group_name",
|
||||
title: "ГК",
|
||||
features: { search: true, multiselect: true, sort: true },
|
||||
},
|
||||
{
|
||||
key: "entity_type",
|
||||
title: "Тип",
|
||||
|
||||
186
src/widgets/CompanyGroupsList/CompanyGroupsList.tsx
Normal file
186
src/widgets/CompanyGroupsList/CompanyGroupsList.tsx
Normal file
@ -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 (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
background: "#fff",
|
||||
borderRight: "1px solid #f0f0f0",
|
||||
borderRadius: 12,
|
||||
}}
|
||||
>
|
||||
<div style={{ padding: "12px 16px", borderBottom:"1px solid #0f172a0f" }}>
|
||||
<Input
|
||||
allowClear
|
||||
prefix={<SearchOutlined style={{ color: "#bfbfbf" }} />}
|
||||
placeholder={"Поиск по ЮЛ или ГСК"}
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ flex: 1, overflowY: "auto", padding: "10px" }}>
|
||||
{loading ? (
|
||||
<div style={{ textAlign: "center", padding: 24 }}>
|
||||
<Spin />
|
||||
</div>
|
||||
) : filtered.length === 0 ? (
|
||||
<Empty
|
||||
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
||||
description="Компании и организации не найдены"
|
||||
style={{ marginTop: 32 }}
|
||||
/>
|
||||
) : (
|
||||
<List
|
||||
dataSource={filtered}
|
||||
split={false}
|
||||
renderItem={(item) => {
|
||||
const active = item.id === activeCompanyGroup?.id;
|
||||
return (
|
||||
<List.Item
|
||||
onClick={() => 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";
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
gap: 12,
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
<Tag
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
width: 28,
|
||||
height: 28,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
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,
|
||||
}}
|
||||
>
|
||||
{item.legal_entities_count}
|
||||
</Tag>
|
||||
</div>
|
||||
</List.Item>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -46,7 +46,7 @@ export function CompanyGroupsTable() {
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%'}}>
|
||||
<Space
|
||||
style={{
|
||||
padding: '16px 12px',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user