import React, { useState, useCallback, useMemo, useEffect } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { useAuth } from '../../contexts/AuthContext'; import { usePlanData } from '../../hooks/usePlanData'; import { useResponsive } from '../../hooks/useResponsive'; import { motion } from 'framer-motion'; import { ArrowLeft, Search, Factory, Droplets, Share2 } from 'lucide-react'; import { PlanGroup } from '../../components/plans/PlanGroup'; import { ShareModal } from '../../components/plans/ShareModal'; import { statusMap } from '../../utils/constants'; import { calculateProgress } from '../../utils/helpers'; import type { PlanWithSteps } from '../../types'; export function PlanOverview() { const navigate = useNavigate(); const [searchParams] = useSearchParams(); const { auth } = useAuth(); const { isMobile } = useResponsive(); // 从 URL 获取过滤参数 const statusFilter = searchParams.get('filter') as 'all' | 'producing' | 'completed' | null; // Tab 状态 const [activeTab, setActiveTab] = useState<'textile' | 'washing'>('textile'); // 搜索 const [searchQuery, setSearchQuery] = useState(''); // 根据 URL 参数设置页面标题 useEffect(() => { if (statusFilter) { const titles: Record = { producing: '进行中计划', completed: '已完成计划' }; document.title = titles[statusFilter] || '计划总览'; } }, [statusFilter]); // 展开状态 const [expandedGroups, setExpandedGroups] = useState>(new Set()); const [expandedPlan, setExpandedPlan] = useState(null); // 分享弹窗 const [shareModal, setShareModal] = useState<{ planId: string; type: 'textile' | 'washing'; factoryName?: string; factoryId?: string; productName?: string; color?: string; colorCode?: string } | null>(null); // 使用优化的数据获取 Hook const { plans, factories, planFactories, operatorNames, loading, loadingMore, hasMore, loadMore, refetch } = usePlanData({ companyId: auth.company?.id || null, pageSize: 20 }); // 根据状态过滤计划 - 必须在 getPlansForFactory 之前声明 const filteredPlansByStatus = useMemo(() => { if (!statusFilter || statusFilter === 'all') return plans; return plans.filter(p => p.status === statusFilter); }, [plans, statusFilter]); // 筛选工厂 const filteredFactories = useMemo(() => factories.filter(f => activeTab === 'textile' ? f.role === 'textile' : f.role === 'washing' ), [factories, activeTab] ); // 获取工厂的计划 const getPlansForFactory = useCallback((factoryId: string) => { const planIds = planFactories .filter(pf => pf.factory_id === factoryId) .map(pf => pf.plan_id); return filteredPlansByStatus.filter(p => planIds.includes(p.id)); }, [planFactories, filteredPlansByStatus]); // 搜索过滤 const filterPlansBySearch = useCallback((plans: PlanWithSteps[]) => { if (!searchQuery) return plans; const query = searchQuery.toLowerCase(); return plans.filter(p => p.product_name.toLowerCase().includes(query) || p.fabric_code.toLowerCase().includes(query) || p.plan_code.toLowerCase().includes(query) ); }, [searchQuery]); // 未关联的计划 const unlinkedPlans = useMemo(() => filteredPlansByStatus.filter(p => !planFactories.some(pf => pf.plan_id === p.id && pf.factory_type === activeTab ) ), [filteredPlansByStatus, planFactories, activeTab] ); // 切换分组展开 const toggleGroup = useCallback((groupId: string) => { setExpandedGroups(prev => { const next = new Set(prev); if (next.has(groupId)) next.delete(groupId); else next.add(groupId); return next; }); }, []); // 切换计划展开 const togglePlan = useCallback((planId: string) => { setExpandedPlan(prev => prev === planId ? null : planId); }, []); // 打开分享弹窗 const openShareModal = useCallback((planId: string, type: 'textile' | 'washing', factoryName?: string, factoryId?: string, productName?: string, color?: string, colorCode?: string) => { setShareModal({ planId, type, factoryName, factoryId, productName, color, colorCode }); }, []); // 关闭分享弹窗 const closeShareModal = useCallback(() => { setShareModal(null); }, []); if (loading) { return (

加载中...

); } return (
{/* Header */}

{statusFilter === 'producing' ? '进行中计划' : statusFilter === 'completed' ? '已完成计划' : '计划总览'}

{statusFilter && ( )}
{/* Tab 切换 */}
{/* 搜索栏 */}
setSearchQuery(e.target.value)} placeholder="搜索产品名称、坯布码、计划编号..." className="w-full pl-9 sm:pl-10 pr-4 py-2.5 sm:py-3 bg-white border border-gray-200 rounded-xl focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all text-sm sm:text-base" />
{/* 已关联工厂的计划 */} {filteredFactories.length > 0 && (
{filteredFactories.map(factory => { const factoryPlans = filterPlansBySearch(getPlansForFactory(factory.id)); if (factoryPlans.length === 0 && searchQuery) return null; return ( toggleGroup(factory.id)} onTogglePlan={togglePlan} onShare={(planId, type, factoryName, factoryId, productName, color, colorCode) => openShareModal(planId, type, factoryName, factoryId, productName, color, colorCode)} onPlanUpdated={refetch} operatorNames={operatorNames} /> ); })}
)} {/* 未关联工厂的计划 */} {unlinkedPlans.length > 0 && ( openShareModal(planId, type, factoryName, factoryId, productName, color, colorCode)} /> )} {/* 加载更多 */} {hasMore && (
)} {/* 空状态 */} {plans.length === 0 && (

暂无计划

请先创建计划

)}
{/* 分享弹窗 */} {shareModal && ( refetch()} /> )}
); } // 未关联计划区域组件 interface UnlinkedPlansSectionProps { plans: PlanWithSteps[]; activeTab: 'textile' | 'washing'; onShare: (planId: string, type: 'textile' | 'washing', factoryName?: string, factoryId?: string, productName?: string, color?: string, colorCode?: string) => void; } function UnlinkedPlansSection({ plans, activeTab, onShare }: UnlinkedPlansSectionProps) { const { isMobile } = useResponsive(); const factoryLabel = activeTab === 'textile' ? '织布厂' : '水洗厂'; return (

待关联{factoryLabel}的计划

点击"分享链接"发送给{factoryLabel},对方确认后即可关联

{plans.map(plan => { const status = statusMap[plan.status] || statusMap.pending; const progress = calculateProgress(plan.completed_quantity, plan.target_quantity); return (

{plan.product_name}-{plan.color}

{status.label}

{plan.fabric_code}-{plan.color_code}

{plan.plan_code}

生产进度 {progress}%
); })}
); }