import React, { useState, useEffect, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { useAuth } from '../../contexts/AuthContext'; import { supabase } from '../../supabase/client'; import { ArrowLeft, Plus, Trash2, Search, X, ChevronDown } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import type { Company } from '../../types'; interface YarnInput { id: string; name: string; ratio: number; yarn_type?: 'warp' | 'weft' | 'all'; } // 产品类型定义(来自产品信息) interface Product { id: string; product_name: string; weight: number; warp_weight: number | null; weft_weight: number | null; total_weight: number | null; color: string; fabric_code: string; color_code: string; production_price: number; image_url: string | null; yarn_usage_per_meter: number; } // 纱线配比类型 interface ProductYarnRatio { id: string; product_id: string; yarn_name: string; ratio: number; yarn_type?: 'warp' | 'weft' | 'all'; } // 纱线类型显示映射 const yarnTypeLabels: Record = { warp: '经线', weft: '纬线', all: '全部' }; export function NewPlan() { const navigate = useNavigate(); const { auth } = useAuth(); // 从产品信息选择的产品 const [selectedProduct, setSelectedProduct] = useState(null); const [products, setProducts] = useState([]); const [productRatios, setProductRatios] = useState>({}); // 搜索和筛选状态 const [searchQuery, setSearchQuery] = useState(''); const [showProductDropdown, setShowProductDropdown] = useState(false); const [showProductModal, setShowProductModal] = useState(false); // 表单字段 const [productName, setProductName] = useState(''); const [color, setColor] = useState(''); const [fabricCode, setFabricCode] = useState(''); const [colorCode, setColorCode] = useState('01'); const [remark, setRemark] = useState(''); const [textileFactory, setTextileFactory] = useState(''); const [targetQuantity, setTargetQuantity] = useState(''); const [productionPrice, setProductionPrice] = useState(''); const [yarns, setYarns] = useState([{ id: '1', name: '', ratio: 1 }]); const [factories, setFactories] = useState([]); const [submitting, setSubmitting] = useState(false); const [loading, setLoading] = useState(true); useEffect(() => { fetchFactories(); fetchProducts(); }, []); // 从产品信息获取产品数据 const fetchProducts = async () => { if (!auth.company) return; setLoading(true); const { data: prodData } = await supabase .from('products') .select('*') .eq('company_id', auth.company.id) .order('created_at', { ascending: false }); if (prodData) { setProducts(prodData as Product[]); // 获取每个产品的纱线配比 const productIds = prodData.map(p => p.id); if (productIds.length > 0) { const { data: ratiosData } = await supabase .from('product_yarn_ratios') .select('*') .in('product_id', productIds); if (ratiosData) { const ratiosMap: Record = {}; ratiosData.forEach((r: any) => { if (!ratiosMap[r.product_id]) ratiosMap[r.product_id] = []; ratiosMap[r.product_id].push(r as ProductYarnRatio); }); setProductRatios(ratiosMap); } } } setLoading(false); }; const fetchFactories = async () => { const { data } = await supabase .from('companies') .select('*') .eq('role', 'textile'); setFactories(data || []); }; // 根据搜索词筛选产品 const filteredProducts = useMemo(() => { if (!searchQuery.trim()) return []; const query = searchQuery.toLowerCase(); return products.filter(product => product.product_name?.toLowerCase().includes(query) || product.fabric_code?.toLowerCase().includes(query) || product.color?.toLowerCase().includes(query) || product.color_code?.toLowerCase().includes(query) ).slice(0, 10); // 最多显示10条 }, [searchQuery, products]); // 选择产品后自动填充表单 const handleSelectProduct = (product: Product) => { setSelectedProduct(product); setProductName(product.product_name); setColor(product.color); setFabricCode(product.fabric_code); setColorCode(product.color_code); setProductionPrice(String(product.production_price || '')); setSearchQuery(`${product.product_name}-${product.weight}g-${product.color}`); setShowProductDropdown(false); setShowProductModal(false); // 自动填充纱线配比 const ratios = productRatios[product.id]; if (ratios && ratios.length > 0) { setYarns(ratios.map((r, i) => ({ id: i.toString(), name: r.yarn_name, ratio: r.ratio, yarn_type: r.yarn_type || 'all' }))); } else { setYarns([{ id: '1', name: '', ratio: 1, yarn_type: 'all' }]); } }; // 清除选择的产品 const handleClearProduct = () => { setSelectedProduct(null); setProductName(''); setColor(''); setFabricCode(''); setColorCode('01'); setProductionPrice(''); setSearchQuery(''); setYarns([{ id: '1', name: '', ratio: 1 }]); }; const addYarn = () => { setYarns([...yarns, { id: Date.now().toString(), name: '', ratio: 1 }]); }; const removeYarn = (id: string) => { if (yarns.length > 1) setYarns(yarns.filter(y => y.id !== id)); }; const updateYarn = (id: string, field: 'name' | 'ratio', value: string | number) => { setYarns(yarns.map(y => y.id === id ? { ...y, [field]: value } : y)); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!auth.company) return; setSubmitting(true); try { // 生成计划编号 const timestamp = Date.now().toString().slice(-6); const planCode = `PLAN-2026-${timestamp}`; // 创建计划 const { data: plan, error: planError } = await supabase .from('production_plans') .insert({ plan_code: planCode, product_name: productName, color: color, fabric_code: fabricCode.toUpperCase(), color_code: colorCode, remark: remark, purchaser_id: auth.company.id, target_quantity: parseInt(targetQuantity) || 0, yarn_usage_per_meter: selectedProduct?.weight || 0, // 使用产品克重作为纱用量 production_price: parseFloat(productionPrice) || 0, status: 'pending', created_by: auth.user?.id }) .select() .maybeSingle(); if (planError) { alert('创建计划失败: ' + planError.message); setSubmitting(false); return; } if (plan && textileFactory) { // 关联纺织厂 await supabase.from('plan_factories').insert({ plan_id: plan.id, factory_id: textileFactory, factory_type: 'textile' }); // 创建纱线配比 for (const yarn of yarns) { if (yarn.name) { const amountPerMeter = selectedProduct?.weight || 0; const totalAmount = amountPerMeter * yarn.ratio * (parseInt(targetQuantity) || 0); await supabase.from('yarn_ratios').insert({ plan_id: plan.id, yarn_name: yarn.name, ratio: yarn.ratio, amount_per_meter: amountPerMeter * yarn.ratio, total_amount: totalAmount }); } } // 创建流程节点 const steps: ('confirm' | 'yarn_purchase' | 'dyeing' | 'machine_start' | 'fabric_warehouse')[] = ['confirm', 'yarn_purchase', 'dyeing', 'machine_start', 'fabric_warehouse']; for (const step of steps) { await supabase.from('plan_process_steps').insert({ plan_id: plan.id, step_type: step, status: 'pending' as const }); } // 记录初始价格(旧价格为0,表示新建) const finalPrice = parseFloat(productionPrice) || 0; if (finalPrice > 0) { await supabase.from('production_price_history').insert({ plan_id: plan.id, old_price: 0, new_price: finalPrice, change_amount: finalPrice, operator_id: auth.user?.id, operator_name: auth.user?.username || '', change_reason: '创建计划时设置初始价格' }); } } alert('计划创建成功!'); navigate('/purchaser/plans'); } catch (err) { alert('创建失败,请重试'); } setSubmitting(false); }; return (

新建纺织计划

{/* 产品信息选择 - 搜索+筛选形式 */}

选择产品

{loading ? (
加载中...
) : products.length === 0 ? (

暂无产品,请先前往生产仓库管理创建产品

) : (
{/* 搜索输入框 */}
{ setSearchQuery(e.target.value); setShowProductDropdown(true); if (!e.target.value) { handleClearProduct(); } }} onFocus={() => setShowProductDropdown(true)} placeholder="搜索产品名称、坯布码、颜色、色号..." className="w-full pl-10 pr-10 py-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" /> {searchQuery && ( )}
{/* 搜索结果下拉框 */} {showProductDropdown && (
{filteredProducts.length > 0 ? ( filteredProducts.map(product => (
handleSelectProduct(product)} className="p-3 hover:bg-blue-50 cursor-pointer border-b last:border-b-0" >
{product.image_url ? ( {product.product_name} ) : (
无图
)}

{product.product_name}-{product.weight}g-{product.color}

产品码: {product.fabric_code} | 色号: {product.color_code} | 价格: ¥{product.production_price || 0}/米

克重: {product.weight}g/m | 经线: {product.warp_weight || '-'}g/m | 纬线: {product.weft_weight || '-'}g/m

)) ) : searchQuery.trim() ? (
未找到匹配的产品
) : (
输入关键词搜索产品
)}
)} {/* 已选择产品展示 */} {selectedProduct && (
{selectedProduct.image_url ? ( {selectedProduct.product_name} ) : (
无图片
)}

已选择产品

{selectedProduct.product_name}-{selectedProduct.weight}g-{selectedProduct.color}

产品码: {selectedProduct.fabric_code} | 色号: {selectedProduct.color_code}

克重: {selectedProduct.weight}g/m | 经线: {selectedProduct.warp_weight || '-'}g/m | 纬线: {selectedProduct.weft_weight || '-'}g/m

)}
)}
{/* 产品信息 - 自动从原坯布产品获取 */}

产品信息

自动从原坯布产品获取

自动从原坯布产品获取

自动从原坯布产品获取

自动从原坯布产品获取

自动从原坯布产品获取

自动从原坯布产品获取

自动从原坯布产品获取

自动从原坯布产品获取

{yarns.filter(y => y.name).map((yarn, idx) => ( {yarnTypeLabels[yarn.yarn_type || 'all']}:{yarn.name}   占比:{Number(yarn.ratio).toFixed(0)}% ))} {!yarns.some(y => y.name) && -}

自动从原坯布产品获取

setRemark(e.target.value)} placeholder="如:60*40,60双股等" className="w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
{/* 生产信息 */}

生产信息

setTargetQuantity(e.target.value)} placeholder="请输入计划产量" required className="w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
setProductionPrice(e.target.value)} placeholder={selectedProduct ? `原坯布价格: ${selectedProduct.production_price || 0} 元/米` : "请输入采购价"} className="w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" /> {selectedProduct && (

已从原坯布产品自动填充,可修改

)}
{/* 产品选择弹窗 */} {showProductModal && ( setShowProductModal(false)} > e.stopPropagation()} > {/* 弹窗头部 */}

选择产品

{/* 搜索框 */}
setSearchQuery(e.target.value)} placeholder="搜索产品名称、坯布码、颜色、色号..." className="w-full pl-10 pr-4 py-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500" />
{/* 产品列表 */}
{filteredProducts.length > 0 ? (
{filteredProducts.map((product) => (
handleSelectProduct(product)} className="p-4 hover:bg-blue-50 cursor-pointer transition-colors" >
{product.image_url ? ( {product.product_name} ) : (
无图
)}

{product.product_name}-{product.weight}g-{product.color}

产品码: {product.fabric_code} 色号: {product.color_code} 价格: ¥{product.production_price || 0}/米
克重: {product.weight}g/m 经线: {product.warp_weight || '-'}g/m 纬线: {product.weft_weight || '-'}g/m 总克重: {product.total_weight || product.weight}g/m
))}
) : searchQuery.trim() ? (

未找到匹配的产品

请尝试其他关键词

) : (

输入关键词搜索产品

)}
{/* 弹窗底部 */}
共 {products.length} 个产品
)}
); }