mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-04 19:02:33 -06:00
Модалка редактирования фасовки в обучении
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { Card, Button, Flex, AutoComplete, InputNumber, Typography, Select } from 'antd';
|
||||
import { Card, Button, Flex, AutoComplete, InputNumber, Typography, Select, Divider } from 'antd';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { CatalogSelect } from './CatalogSelect';
|
||||
import type { CatalogItem, UnmatchedItem, ProductSearchResult } from '../../services/types';
|
||||
import { CreateContainerModal } from '../invoices/CreateContainerModal'; // Импортируем модалку
|
||||
import type { CatalogItem, UnmatchedItem, ProductSearchResult, ProductContainer } from '../../services/types';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
interface Props {
|
||||
catalog: CatalogItem[]; // Оставляем для совместимости, но CatalogSelect его больше не использует
|
||||
catalog: CatalogItem[];
|
||||
unmatched?: UnmatchedItem[];
|
||||
onSave: (rawName: string, productId: string, quantity: number, containerId?: string) => void;
|
||||
isLoading: boolean;
|
||||
@@ -15,13 +16,19 @@ interface Props {
|
||||
|
||||
export const AddMatchForm: React.FC<Props> = ({ catalog, unmatched = [], onSave, isLoading }) => {
|
||||
const [rawName, setRawName] = useState('');
|
||||
|
||||
// Состояния товара
|
||||
const [selectedProduct, setSelectedProduct] = useState<string | undefined>(undefined);
|
||||
// Сохраняем полный объект товара, полученный из поиска, чтобы иметь доступ к containers
|
||||
const [selectedProductData, setSelectedProductData] = useState<ProductSearchResult | undefined>(undefined);
|
||||
|
||||
const [quantity, setQuantity] = useState<number | null>(1);
|
||||
const [selectedContainer, setSelectedContainer] = useState<string | null>(null);
|
||||
|
||||
// Состояние модалки создания фасовки
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
// --- Вычисляемые значения ---
|
||||
|
||||
const unmatchedOptions = useMemo(() => {
|
||||
return unmatched.map(item => ({
|
||||
value: item.raw_name,
|
||||
@@ -29,32 +36,24 @@ export const AddMatchForm: React.FC<Props> = ({ catalog, unmatched = [], onSave,
|
||||
}));
|
||||
}, [unmatched]);
|
||||
|
||||
// Вычисляем активный товар: либо из результатов поиска, либо ищем в старом каталоге (если он передан)
|
||||
// Активный продукт (из поиска или из старого каталога)
|
||||
const activeProduct = useMemo(() => {
|
||||
if (selectedProductData) return selectedProductData;
|
||||
if (selectedProduct && catalog.length > 0) {
|
||||
// Приводим типы, так как CatalogItem расширяет ProductSearchResult
|
||||
return catalog.find(item => item.id === selectedProduct) as unknown as ProductSearchResult;
|
||||
}
|
||||
return null;
|
||||
return undefined;
|
||||
}, [selectedProduct, selectedProductData, catalog]);
|
||||
|
||||
// Хендлер смены товара: принимаем и ID, и объект
|
||||
const handleProductChange = (val: string, productObj?: ProductSearchResult) => {
|
||||
setSelectedProduct(val);
|
||||
if (productObj) {
|
||||
setSelectedProductData(productObj);
|
||||
}
|
||||
setSelectedContainer(null);
|
||||
};
|
||||
|
||||
// Список контейнеров текущего товара
|
||||
const containers = useMemo(() => {
|
||||
return activeProduct?.containers || [];
|
||||
}, [activeProduct]);
|
||||
|
||||
// Берем единицу измерения с учетом новой структуры (main_unit)
|
||||
// Базовая единица
|
||||
const baseUom = activeProduct?.main_unit?.name || activeProduct?.measure_unit || 'ед.';
|
||||
|
||||
// Текстовое отображение текущей единицы
|
||||
const currentUomName = useMemo(() => {
|
||||
if (selectedContainer) {
|
||||
const cont = containers.find(c => c.id === selectedContainer);
|
||||
@@ -63,10 +62,23 @@ export const AddMatchForm: React.FC<Props> = ({ catalog, unmatched = [], onSave,
|
||||
return baseUom;
|
||||
}, [selectedContainer, containers, baseUom]);
|
||||
|
||||
const isButtonDisabled = !rawName.trim() || !selectedProduct || !quantity || quantity <= 0 || isLoading;
|
||||
|
||||
// --- Хендлеры ---
|
||||
|
||||
const handleProductChange = (val: string, productObj?: ProductSearchResult) => {
|
||||
setSelectedProduct(val);
|
||||
if (productObj) {
|
||||
setSelectedProductData(productObj);
|
||||
}
|
||||
setSelectedContainer(null);
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (rawName.trim() && selectedProduct && quantity && quantity > 0) {
|
||||
onSave(rawName, selectedProduct, quantity, selectedContainer || undefined);
|
||||
|
||||
// Сброс формы
|
||||
setRawName('');
|
||||
setSelectedProduct(undefined);
|
||||
setSelectedProductData(undefined);
|
||||
@@ -75,11 +87,32 @@ export const AddMatchForm: React.FC<Props> = ({ catalog, unmatched = [], onSave,
|
||||
}
|
||||
};
|
||||
|
||||
const isButtonDisabled = !rawName.trim() || !selectedProduct || !quantity || quantity <= 0 || isLoading;
|
||||
// Обработка создания новой фасовки
|
||||
const handleContainerCreated = (newContainer: ProductContainer) => {
|
||||
setIsModalOpen(false);
|
||||
|
||||
// 1. Обновляем локальные данные продукта, добавляя новую фасовку в список
|
||||
if (selectedProductData) {
|
||||
setSelectedProductData({
|
||||
...selectedProductData,
|
||||
containers: [...(selectedProductData.containers || []), newContainer]
|
||||
});
|
||||
} else if (activeProduct) {
|
||||
// Если продукт был взят из общего catalog, создаем локальную копию
|
||||
setSelectedProductData({
|
||||
...activeProduct,
|
||||
containers: [...(activeProduct.containers || []), newContainer]
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Сразу выбираем созданную фасовку
|
||||
setSelectedContainer(newContainer.id);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card title="Добавить новую связь" size="small" style={{ marginBottom: 16 }}>
|
||||
<Flex vertical gap="middle">
|
||||
{/* Поле текста из чека */}
|
||||
<div>
|
||||
<div style={{ marginBottom: 4, fontSize: 12, color: '#888' }}>Текст из чека:</div>
|
||||
<AutoComplete
|
||||
@@ -94,23 +127,25 @@ export const AddMatchForm: React.FC<Props> = ({ catalog, unmatched = [], onSave,
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Выбор товара (Поиск) */}
|
||||
<div>
|
||||
<div style={{ marginBottom: 4, fontSize: 12, color: '#888' }}>Товар в iiko:</div>
|
||||
<CatalogSelect
|
||||
// Удален проп catalog={catalog}, так как компонент теперь ищет товары сам
|
||||
value={selectedProduct}
|
||||
onChange={handleProductChange}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{containers.length > 0 && (
|
||||
{/* Выбор фасовки (появляется только если есть активный товар) */}
|
||||
{activeProduct && (
|
||||
<div>
|
||||
<div style={{ marginBottom: 4, fontSize: 12, color: '#888' }}>Единица измерения / Фасовка:</div>
|
||||
<Select
|
||||
style={{ width: '100%' }}
|
||||
value={selectedContainer}
|
||||
onChange={setSelectedContainer}
|
||||
placeholder="Выберите ед. измерения"
|
||||
options={[
|
||||
{ value: null, label: `Базовая единица (${baseUom})` },
|
||||
...containers.map(c => ({
|
||||
@@ -118,10 +153,27 @@ export const AddMatchForm: React.FC<Props> = ({ catalog, unmatched = [], onSave,
|
||||
label: `${c.name} (=${Number(c.count)} ${baseUom})`
|
||||
}))
|
||||
]}
|
||||
// Рендерим кнопку добавления внизу выпадающего списка
|
||||
dropdownRender={(menu) => (
|
||||
<>
|
||||
{menu}
|
||||
<Divider style={{ margin: '4px 0' }} />
|
||||
<Button
|
||||
type="text"
|
||||
block
|
||||
icon={<PlusOutlined />}
|
||||
onClick={() => setIsModalOpen(true)}
|
||||
style={{ textAlign: 'left' }}
|
||||
>
|
||||
Добавить фасовку
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Количество */}
|
||||
<div>
|
||||
<div style={{ marginBottom: 4, fontSize: 12, color: '#888' }}>
|
||||
Количество (в выбранных единицах):
|
||||
@@ -139,6 +191,7 @@ export const AddMatchForm: React.FC<Props> = ({ catalog, unmatched = [], onSave,
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Кнопка сохранения */}
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
@@ -150,6 +203,17 @@ export const AddMatchForm: React.FC<Props> = ({ catalog, unmatched = [], onSave,
|
||||
Сохранить связь
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
{/* Модальное окно создания фасовки */}
|
||||
{activeProduct && (
|
||||
<CreateContainerModal
|
||||
visible={isModalOpen}
|
||||
onCancel={() => setIsModalOpen(false)}
|
||||
productId={activeProduct.id}
|
||||
productBaseUnit={baseUom}
|
||||
onSuccess={handleContainerCreated}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user