Merge remote-tracking branch 'origin/main' into fix/1916-files-pagination
This commit is contained in:
commit
257002035f
@ -156,3 +156,8 @@ body {
|
|||||||
font-family: "Geist", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
|
font-family: "Geist", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Подписи полей во всех формах полужирные */
|
||||||
|
.ant-form-item-label > label {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|||||||
@ -50,7 +50,7 @@ createRoot(rootElement).render(
|
|||||||
},
|
},
|
||||||
Form: {
|
Form: {
|
||||||
labelFontSize: 12,
|
labelFontSize: 12,
|
||||||
labelColor: '#667085',
|
labelColor: '#101828',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}>
|
}}>
|
||||||
|
|||||||
@ -45,6 +45,7 @@ export function CatalogueJur() {
|
|||||||
{createFormOpen && (
|
{createFormOpen && (
|
||||||
<CatalogueJurForm
|
<CatalogueJurForm
|
||||||
open={createFormOpen}
|
open={createFormOpen}
|
||||||
|
outsideGroup={outside_group}
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
setCreateFormOpen(false);
|
setCreateFormOpen(false);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ const initialState: CatalogueJurSliceType = {
|
|||||||
total_groups: 0,
|
total_groups: 0,
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
|
currentRequestId: null,
|
||||||
isGettingArchive: false,
|
isGettingArchive: false,
|
||||||
relatedGroupFilter: null,
|
relatedGroupFilter: null,
|
||||||
activeCompanyGroup: null,
|
activeCompanyGroup: null,
|
||||||
@ -29,21 +30,33 @@ const catalogueJurSlice = createSlice({
|
|||||||
state.activeCompanyGroup = action.payload;
|
state.activeCompanyGroup = action.payload;
|
||||||
state.relatedGroupFilter = null;
|
state.relatedGroupFilter = null;
|
||||||
},
|
},
|
||||||
|
resetRows(state) {
|
||||||
|
state.raw_rows = [];
|
||||||
|
state.total_groups = 0;
|
||||||
|
// Запрос, начатый до сброса, больше не нужен: его ответ отбросится в fulfilled/rejected
|
||||||
|
state.currentRequestId = null;
|
||||||
|
state.loading = false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
extraReducers: (builder) => {
|
extraReducers: (builder) => {
|
||||||
builder
|
builder
|
||||||
.addCase(getCatalogueJurThunk.pending, (state, _) => {
|
.addCase(getCatalogueJurThunk.pending, (state, action) => {
|
||||||
|
state.currentRequestId = action.meta.requestId;
|
||||||
state.loading = true;
|
state.loading = true;
|
||||||
state.error = null;
|
state.error = null;
|
||||||
})
|
})
|
||||||
.addCase(getCatalogueJurThunk.fulfilled, (state, action) => {
|
.addCase(getCatalogueJurThunk.fulfilled, (state, action) => {
|
||||||
|
if (action.meta.requestId !== state.currentRequestId) return;
|
||||||
state.raw_rows = action.payload.items;
|
state.raw_rows = action.payload.items;
|
||||||
state.total_groups = action.payload.total;
|
state.total_groups = action.payload.total;
|
||||||
state.loading = false;
|
state.loading = false;
|
||||||
|
state.currentRequestId = null;
|
||||||
})
|
})
|
||||||
.addCase(getCatalogueJurThunk.rejected, (state, action) => {
|
.addCase(getCatalogueJurThunk.rejected, (state, action) => {
|
||||||
|
if (action.meta.requestId !== state.currentRequestId) return;
|
||||||
state.error = action.payload ?? 'Неизвестная ошибка';
|
state.error = action.payload ?? 'Неизвестная ошибка';
|
||||||
state.loading = false;
|
state.loading = false;
|
||||||
|
state.currentRequestId = null;
|
||||||
})
|
})
|
||||||
// Выбранная ГК — копия строки списка ГК: после перезагрузки списка берём свежую (счётчик ЮЛ в шапке и вкладке)
|
// Выбранная ГК — копия строки списка ГК: после перезагрузки списка берём свежую (счётчик ЮЛ в шапке и вкладке)
|
||||||
.addCase(getCompanyGroupsThunk.fulfilled, (state, action) => {
|
.addCase(getCompanyGroupsThunk.fulfilled, (state, action) => {
|
||||||
@ -54,5 +67,5 @@ const catalogueJurSlice = createSlice({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { setIsGettingArchive, setRelatedGroupFilter, setActiveCompanyGroup } = catalogueJurSlice.actions;
|
export const { setIsGettingArchive, setRelatedGroupFilter, setActiveCompanyGroup, resetRows } = catalogueJurSlice.actions;
|
||||||
export default catalogueJurSlice.reducer;
|
export default catalogueJurSlice.reducer;
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export interface CatalogueJurSliceType {
|
|||||||
raw_rows: ICatalogueJur[];
|
raw_rows: ICatalogueJur[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
|
currentRequestId: string | null;
|
||||||
isGettingArchive: boolean;
|
isGettingArchive: boolean;
|
||||||
relatedGroupFilter?: RelatedGroupOut | null;
|
relatedGroupFilter?: RelatedGroupOut | null;
|
||||||
activeCompanyGroup?: ICompanyGroup | null;
|
activeCompanyGroup?: ICompanyGroup | null;
|
||||||
|
|||||||
@ -1,9 +1,67 @@
|
|||||||
.ant-tabs-tab-active {
|
.catalogue-company-group-tabs {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalogue-company-group-tabs .ant-tabs-nav {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalogue-company-group-tabs .ant-tabs-nav-list {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalogue-company-group-tabs .ant-tabs-tab {
|
||||||
|
padding: 8px 12px !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalogue-company-group-tabs .ant-tabs-tab-active {
|
||||||
background-color: #ecfdf3 !important;
|
background-color: #ecfdf3 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-tabs-tab {
|
.catalogue-company-group-tabs .ant-tabs-tab-btn {
|
||||||
padding: 8px 12px !important;
|
display: flex;
|
||||||
margin: 10px 0 0 0 !important;
|
align-items: center;
|
||||||
border-radius: 8px !important;
|
font-size: 14px;
|
||||||
|
line-height: 1;
|
||||||
|
color: #667085 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.catalogue-company-group-tabs .ant-tabs-tab-active .ant-tabs-tab-btn {
|
||||||
|
color: #166534 !important;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalogue-company-group-tabs .ant-tabs-ink-bar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalogue-company-group-tabs__label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalogue-company-group-tabs__count {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
padding: 0 6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: #f0f2f5;
|
||||||
|
color: #667085;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catalogue-company-group-tabs .ant-tabs-tab-active .catalogue-company-group-tabs__count {
|
||||||
|
background-color: transparent;
|
||||||
|
color: #166534;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
@ -11,22 +11,34 @@ interface CatalogueCompanyGroupTabsI {
|
|||||||
|
|
||||||
export type CatalogueCompanyGroupTabKey = 'legal_entities' | 'gsk' | 'gsz';
|
export type CatalogueCompanyGroupTabKey = 'legal_entities' | 'gsk' | 'gsz';
|
||||||
|
|
||||||
|
const TabLabel = ({ title, count }: { title: string; count: number }) => (
|
||||||
|
<span className='catalogue-company-group-tabs__label'>
|
||||||
|
<span>{title}</span>
|
||||||
|
<span className='catalogue-company-group-tabs__count'>{count}</span>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
export const CatalogueCompanyGroupTabs = ({ activeTab, setActiveTab, gskData, gszData }: CatalogueCompanyGroupTabsI) => {
|
export const CatalogueCompanyGroupTabs = ({ activeTab, setActiveTab, gskData, gszData }: CatalogueCompanyGroupTabsI) => {
|
||||||
const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup);
|
const activeCompanyGroup = useAppSelector((state) => state.catalogue_jur.activeCompanyGroup);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
|
className='catalogue-company-group-tabs'
|
||||||
activeKey={activeTab}
|
activeKey={activeTab}
|
||||||
onChange={(key) => setActiveTab(key as CatalogueCompanyGroupTabKey)}
|
onChange={(key) => setActiveTab(key as CatalogueCompanyGroupTabKey)}
|
||||||
tabBarStyle={{ margin: 0, marginBottom: 0 }}
|
|
||||||
style={{ marginBottom: 0 }}
|
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
key: 'legal_entities',
|
key: 'legal_entities',
|
||||||
label: `ЮЛ ${activeCompanyGroup?.legal_entities_count ?? 0}`,
|
label: <TabLabel title='ЮЛ' count={activeCompanyGroup?.legal_entities_count ?? 0} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'gsk',
|
||||||
|
label: <TabLabel title='ГСК' count={gskData.length} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'gsz',
|
||||||
|
label: <TabLabel title='ГСЗ' count={gszData.length} />,
|
||||||
},
|
},
|
||||||
{ key: 'gsk', label: `ГСК ${gskData?.length ?? 0}` },
|
|
||||||
{ key: 'gsz', label: `ГСЗ ${gszData?.length ?? 0}` },
|
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -16,6 +16,7 @@ type Props = {
|
|||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onOk: (values: CatalogueJurFormProps) => void | Promise<void>;
|
onOk: (values: CatalogueJurFormProps) => void | Promise<void>;
|
||||||
jurId?: string;
|
jurId?: string;
|
||||||
|
outsideGroup?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ошибки сервера, относящиеся к одному полю, показываем у этого поля
|
// Ошибки сервера, относящиеся к одному полю, показываем у этого поля
|
||||||
@ -26,7 +27,7 @@ const FIELD_BY_ERROR_CODE: Record<string, keyof CatalogueJurFormProps> = {
|
|||||||
CRM_ID_EXISTS: 'crm_id',
|
CRM_ID_EXISTS: 'crm_id',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId }) => {
|
export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId, outsideGroup = false }) => {
|
||||||
const [form] = Form.useForm<CatalogueJurFormProps>();
|
const [form] = Form.useForm<CatalogueJurFormProps>();
|
||||||
const notification = useNotificationApi();
|
const notification = useNotificationApi();
|
||||||
const [initialDataLoading, setInitialDataLoading] = useState(false);
|
const [initialDataLoading, setInitialDataLoading] = useState(false);
|
||||||
@ -67,7 +68,9 @@ export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId
|
|||||||
} finally {
|
} finally {
|
||||||
setInitialDataLoading(false);
|
setInitialDataLoading(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!outsideGroup) {
|
||||||
|
// Создание из карточки ГК: подставляем выбранную ГК. В «ЮЛ вне ГК» не подставляем —
|
||||||
|
// выбранная ГК остаётся в сторе после ухода со страницы «ГК и организации».
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
company_group_id: activeCompanyGroup?.id ?? undefined,
|
company_group_id: activeCompanyGroup?.id ?? undefined,
|
||||||
});
|
});
|
||||||
@ -253,7 +256,7 @@ export const CatalogueJurForm: React.FC<Props> = ({ open, onCancel, onOk, jurId
|
|||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item name='company_group_id' label='ГК'>
|
<Form.Item name='company_group_id' label='ГК'>
|
||||||
<Select
|
<Select
|
||||||
disabled={!!jurId}
|
disabled={!!jurId || outsideGroup}
|
||||||
allowClear
|
allowClear
|
||||||
placeholder='— не указан —'
|
placeholder='— не указан —'
|
||||||
options={companyGroupOptions}
|
options={companyGroupOptions}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { ApiError } from '../../../api/client';
|
import { ApiError } from '../../../api/client';
|
||||||
import { ColumnSettings, DataTable, useFilteredRows, useTableFilters, useVisibleColumns } from '../../../components/GenericTable';
|
import { ColumnSettings, DataTable, useFilteredRows, useTableFilters, useVisibleColumns } from '../../../components/GenericTable';
|
||||||
import { editCatalogueJur, moveCatalogueJur, withdrawCatalogueJur } from '../../../services/api/directories/catalogue_jur';
|
import { editCatalogueJur, moveCatalogueJur, withdrawCatalogueJur } from '../../../services/api/directories/catalogue_jur';
|
||||||
import { setIsGettingArchive, setRelatedGroupFilter } from '../../../store/slices/catalogueJurSlice/catalogueJurSlice';
|
import { resetRows, setIsGettingArchive, setRelatedGroupFilter } from '../../../store/slices/catalogueJurSlice/catalogueJurSlice';
|
||||||
import { getCatalogueJurThunk } from '../../../store/slices/catalogueJurSlice/thunks';
|
import { getCatalogueJurThunk } from '../../../store/slices/catalogueJurSlice/thunks';
|
||||||
import { getCompanyGroupsThunk } from '../../../store/slices/companyGroupsSlice/thunks';
|
import { getCompanyGroupsThunk } from '../../../store/slices/companyGroupsSlice/thunks';
|
||||||
import { useAppDispatch, useAppSelector } from '../../../store/store';
|
import { useAppDispatch, useAppSelector } from '../../../store/store';
|
||||||
@ -136,6 +136,12 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur
|
|||||||
}
|
}
|
||||||
}, [isGettingArchive, activeCompanyGroup, outside_group]);
|
}, [isGettingArchive, activeCompanyGroup, outside_group]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
dispatch(resetRows());
|
||||||
|
};
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
const extraColumns: ColumnsType<ICatalogueJur> = useMemo(
|
const extraColumns: ColumnsType<ICatalogueJur> = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
@ -213,7 +219,7 @@ export function CatalogueJurTable({ outside_group, tabsComponent }: CatalogueJur
|
|||||||
<Input
|
<Input
|
||||||
allowClear
|
allowClear
|
||||||
prefix={<SearchOutlined />}
|
prefix={<SearchOutlined />}
|
||||||
placeholder='Поиск по ГК, CRM ID или РФ'
|
placeholder='Поиск по ЮЛ или ИНН'
|
||||||
value={rawQuery}
|
value={rawQuery}
|
||||||
onChange={(e) => setRawQuery(e.target.value)}
|
onChange={(e) => setRawQuery(e.target.value)}
|
||||||
style={{ maxWidth: 320 }}
|
style={{ maxWidth: 320 }}
|
||||||
|
|||||||
@ -39,7 +39,7 @@ export const catalogueJurConfig: TableConfig<ICatalogueJur> = {
|
|||||||
title: 'Тип',
|
title: 'Тип',
|
||||||
features: { multiselect: true, sort: true },
|
features: { multiselect: true, sort: true },
|
||||||
render: (val) => {
|
render: (val) => {
|
||||||
const preset = val === 'ЮЛ' ? TAG_PRESETS.orange : TAG_PRESETS.purple;
|
const preset = val === 'ЮЛ' ? TAG_PRESETS.purple : TAG_PRESETS.orange;
|
||||||
return <TableTag text={val as string} {...preset} />;
|
return <TableTag text={val as string} {...preset} />;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -111,7 +111,7 @@ export const RelatedGroupForm: React.FC<Props> = ({ open, onCancel, onOk, relate
|
|||||||
loading={initialDataLoading}
|
loading={initialDataLoading}
|
||||||
confirmLoading={confirmLoading}>
|
confirmLoading={confirmLoading}>
|
||||||
<Form form={form} layout='vertical'>
|
<Form form={form} layout='vertical'>
|
||||||
<FormItem name='crm_id' label='ID в CRM'>
|
<FormItem name='crm_id' label={`ID ${kind === 'gsk' ? 'ГСК' : 'ГСЗ'} в CRM`}>
|
||||||
<Input />
|
<Input />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
<FormItem name='name' label='Наименование' rules={[{ required: true, message: 'Укажите наименование' }]}>
|
<FormItem name='name' label='Наименование' rules={[{ required: true, message: 'Укажите наименование' }]}>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user