═══════════════════════════════════════════════════════════════════════════════
                        程序鉴别材料 - 源代码前30页
                    纺织行业采购计划管理系统 V1.0.0
═══════════════════════════════════════════════════════════════════════════════

【文件1】src/index.tsx - 应用入口文件
───────────────────────────────────────────────────────────────────────────────
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './styles/index.css';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

【文件2】src/App.tsx - 根组件与路由配置
───────────────────────────────────────────────────────────────────────────────
import React, { useState } from 'react';
import { HashRouter, Routes, Route, Navigate, useLocation } from 'react-router-dom';
import { AnimatePresence, motion } from 'framer-motion';
import { AuthProvider } from './contexts/AuthContext';
import { ErrorBoundary, PageErrorBoundary } from './components/ErrorBoundary';
import { LoginPage } from './pages/LoginPage';
import { RegisterPage } from './pages/RegisterPage';
import { RoleSelectPage } from './pages/RoleSelectPage';
import { PurchaserDashboard } from './pages/purchaser/Dashboard';
import { TextileDashboard } from './pages/textile/Dashboard';
import { WashingDashboard } from './pages/washing/Dashboard';
import { PlanOverview } from './pages/purchaser/PlanOverview';
import { NewPlan } from './pages/purchaser/NewPlan';
import { WarehouseManage } from './pages/purchaser/WarehouseManage';
import { FactoryManage } from './pages/purchaser/FactoryManage';
import { TextilePlanOverview } from './pages/textile/PlanOverview';
import { YarnWarehouse } from './pages/textile/YarnWarehouse';
import { FabricWarehouse } from './pages/textile/FabricWarehouse';
import { PaymentPending } from './pages/textile/PaymentPending';
import { MemberManage } from './pages/MemberManage';
import { ImportPlanPage } from './pages/ImportPlanPage';
import { NetworkStatusBar } from './components/NetworkStatusBar';
import './styles/index.css';

// 页面过渡动画配置
const pageTransitionVariants = {
  initial: { opacity: 0, y: 20, scale: 0.98 },
  animate: {
    opacity: 1, y: 0, scale: 1,
    transition: { duration: 0.35, ease: [0.25, 0.46, 0.45, 0.94] }
  },
  exit: {
    opacity: 0, y: -10, scale: 0.98,
    transition: { duration: 0.25, ease: [0.25, 0.46, 0.45, 0.94] }
  },
};

function AnimatedRoute({ children, pageName }: { children: React.ReactNode; pageName?: string }) {
  return (
    <motion.div variants={pageTransitionVariants} initial="initial" animate="animate" exit="exit"
      style={{ willChange: 'transform, opacity' }}>
      <PageErrorBoundary pageName={pageName}>{children}</PageErrorBoundary>
    </motion.div>
  );
}

function AppRoutes() {
  const location = useLocation();
  return (
    <AnimatePresence mode="wait">
      <Routes location={location} key={location.pathname}>
        <Route path="/login" element={<AnimatedRoute pageName="登录"><LoginPage /></AnimatedRoute>} />
        <Route path="/register" element={<AnimatedRoute pageName="注册"><RegisterPage /></AnimatedRoute>} />
        <Route path="/role-select" element={<AnimatedRoute pageName="角色选择"><RoleSelectPage /></AnimatedRoute>} />
        <Route path="/purchaser" element={<AnimatedRoute pageName="采购商首页"><PurchaserDashboard /></AnimatedRoute>} />
        <Route path="/purchaser/plans" element={<AnimatedRoute pageName="计划总览"><PlanOverview /></AnimatedRoute>} />
        <Route path="/purchaser/plans/new" element={<AnimatedRoute pageName="新建计划"><NewPlan /></AnimatedRoute>} />
        <Route path="/purchaser/warehouse" element={<AnimatedRoute pageName="仓库管理"><WarehouseManage /></AnimatedRoute>} />
        <Route path="/purchaser/factories" element={<AnimatedRoute pageName="工厂管理"><FactoryManage /></AnimatedRoute>} />
        <Route path="/textile" element={<AnimatedRoute pageName="纺织厂首页"><TextileDashboard /></AnimatedRoute>} />
        <Route path="/textile/plans" element={<AnimatedRoute pageName="纺织厂计划"><TextilePlanOverview /></AnimatedRoute>} />
        <Route path="/textile/fabric-warehouse" element={<AnimatedRoute pageName="坯布仓库"><FabricWarehouse /></AnimatedRoute>} />
        <Route path="/textile/yarn-warehouse" element={<AnimatedRoute pageName="纱线仓库"><YarnWarehouse /></AnimatedRoute>} />
        <Route path="/textile/payments" element={<AnimatedRoute pageName="待结款"><PaymentPending /></AnimatedRoute>} />
        <Route path="/washing" element={<AnimatedRoute pageName="水洗厂首页"><WashingDashboard /></AnimatedRoute>} />
        <Route path="/members" element={<AnimatedRoute pageName="子账号管理"><MemberManage /></AnimatedRoute>} />
        <Route path="/import" element={<AnimatedRoute pageName="导入计划"><ImportPlanPage /></AnimatedRoute>} />
        <Route path="/" element={<Navigate to="/login" replace />} />
      </Routes>
    </AnimatePresence>
  );
}

function App() {
  return (
    <ErrorBoundary>
      <AuthProvider>
        <HashRouter>
          <NetworkStatusBar />
          <AppRoutes />
        </HashRouter>
      </AuthProvider>
    </ErrorBoundary>
  );
}

export default App;

【文件3】src/contexts/AuthContext.tsx - 认证上下文（部分）
───────────────────────────────────────────────────────────────────────────────
import React, { createContext, useContext, useState, useCallback, useEffect } from 'react';
import { supabase } from '../supabase/client';
import type { Profile, Company, UserRole, AuthState } from '../types';
import { encryptPhone, decryptPhone } from '../utils/crypto';

interface RegisterData {
  username: string;
  password: string;
  displayName: string;
  companyName: string;
  phone: string;
  role: UserRole;
}

interface AuthContextType {
  auth: AuthState;
  login: (username: string, password: string) => Promise<boolean>;
  register: (data: RegisterData) => Promise<{ success: boolean; error?: string }>;
  logout: () => Promise<void>;
  selectRole: (role: UserRole) => void;
  loading: boolean;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [auth, setAuth] = useState<AuthState>({
    isLoggedIn: false, user: null, company: null, currentRole: null
  });
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const initAuth = async () => {
      const { data: { session } } = await supabase.auth.getSession();
      if (session?.user) {
        const { data: profile } = await supabase
          .from('profiles').select('*').eq('id', session.user.id).maybeSingle();
        if (profile) {
          let company: Company | null = null;
          if (profile.company_id) {
            const { data: comp } = await supabase
              .from('companies').select('*').eq('id', profile.company_id).maybeSingle();
            company = comp;
          }
          setAuth({ isLoggedIn: true, user: profile, company, currentRole: company?.role || null });
        }
      }
      setLoading(false);
    };
    initAuth();

    const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, session) => {
      if (event === 'SIGNED_IN' && session?.user) {
        setTimeout(async () => {
          const { data: profile } = await supabase
            .from('profiles').select('*').eq('id', session.user.id).maybeSingle();
          if (profile) {
            let company: Company | null = null;
            if (profile.company_id) {
              const { data: comp } = await supabase
                .from('companies').select('*').eq('id', profile.company_id).maybeSingle();
              company = comp;
            }
            setAuth({ isLoggedIn: true, user: profile, company, currentRole: company?.role || null });
          }
        }, 0);
      } else if (event === 'SIGNED_OUT') {
        setAuth({ isLoggedIn: false, user: null, company: null, currentRole: null });
      }
    });
    return () => subscription.unsubscribe();
  }, []);

  const login = useCallback(async (username: string, password: string): Promise<boolean> => {
    const { error } = await supabase.auth.signInWithPassword({
      email: `${username}@meoo.local`, password,
    });
    return !error;
  }, []);

  const register = useCallback(async (data: RegisterData) => {
    try {
      const { data: companyData, error: companyError } = await supabase
        .from('companies').insert({ name: data.companyName, role: data.role, contact_phone: data.phone })
        .select().single();
      if (companyError || !companyData) return { success: false, error: '创建公司失败' };

      const { data: authData, error: authError } = await supabase.auth.signUp({
        email: `${data.username}@meoo.local`, password: data.password,
      });
      if (authError || !authData.user) {
        await supabase.from('companies').delete().eq('id', companyData.id);
        return { success: false, error: '注册失败' };
      }

      const { error: profileError } = await supabase.from('profiles').insert({
        id: authData.user.id, username: data.username, display_name: data.displayName,
        phone: encryptPhone(data.phone), company_id: companyData.id, is_master: true
      });
      if (profileError) {
        await supabase.from('companies').delete().eq('id', companyData.id);
        return { success: false, error: '创建用户资料失败' };
      }
      return { success: true };
    } catch (err: any) {
      return { success: false, error: err?.message || '注册失败' };
    }
  }, []);

  const logout = useCallback(async () => {
    await supabase.auth.signOut();
    setAuth({ isLoggedIn: false, user: null, company: null, currentRole: null });
  }, []);

  const selectRole = useCallback((role: UserRole) => {
    setAuth(prev => ({ ...prev, currentRole: role }));
  }, []);

  return (
    <AuthContext.Provider value={{ auth, login, register, logout, selectRole, loading }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const context = useContext(AuthContext);
  if (!context) throw new Error('useAuth must be used within AuthProvider');
  return context;
}

【文件4】src/supabase/client.ts - Supabase客户端配置
───────────────────────────────────────────────────────────────────────────────
import { createClient } from '@supabase/supabase-js';
import type { Database } from './types';

export function getSupabaseUrl(): string {
  return `${(window as any).MEOO_CONFIG?.meoo_app_access_url || location.origin}/sb-api`;
}

export const supabaseUrl = getSupabaseUrl();
export const supabaseAnonKey = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...';

export const supabase = createClient<Database>(supabaseUrl, supabaseAnonKey, {
  auth: { persistSession: true, autoRefreshToken: true },
});

【文件5】src/types/index.ts - 类型定义（部分）
───────────────────────────────────────────────────────────────────────────────
export type UserRole = 'purchaser' | 'textile' | 'washing';
export type PlanStatus = 'pending' | 'producing' | 'completed';
export type FactoryType = 'textile' | 'washing';

export interface Profile {
  id: string;
  username: string;
  display_name?: string;
  phone?: string;
  company_id?: string;
  is_master: boolean;
  master_id?: string;
  created_at: string;
}

export interface Company {
  id: string;
  name: string;
  role: UserRole;
  address?: string;
  contact_phone?: string;
  created_at: string;
}

export interface ProductionPlan {
  id: string;
  plan_code: string;
  product_name: string;
  color: string;
  fabric_code: string;
  color_code: string;
  remark?: string;
  purchaser_id: string;
  target_quantity: number;
  completed_quantity: number;
  yarn_usage_per_meter: number;
  production_price: number;
  status: PlanStatus;
  start_time?: string;
  created_by: string;
  created_at: string;
  updated_at: string;
}

export interface AuthState {
  isLoggedIn: boolean;
  user: Profile | null;
  company: Company | null;
  currentRole: UserRole | null;
}

【文件6】src/hooks/useNetworkStatus.ts - 网络状态Hook（部分）
───────────────────────────────────────────────────────────────────────────────
import { useState, useEffect, useCallback, useRef } from 'react';

interface NetworkState {
  isOnline: boolean;
  isSlowConnection: boolean;
  lastOnlineTime: number | null;
}

interface QueuedOperation {
  id: string;
  operation: () => Promise<void>;
  retryCount: number;
  maxRetries: number;
  onSuccess?: () => void;
  onError?: (error: Error) => void;
}

export function useNetworkStatus() {
  const [state, setState] = useState<NetworkState>({
    isOnline: navigator.onLine,
    isSlowConnection: false,
    lastOnlineTime: navigator.onLine ? Date.now() : null
  });
  const queueRef = useRef<QueuedOperation[]>([]);
  const processingRef = useRef(false);

  useEffect(() => {
    const handleOnline = () => {
      setState(prev => ({ ...prev, isOnline: true, lastOnlineTime: Date.now() }));
      processQueue();
    };
    const handleOffline = () => {
      setState(prev => ({ ...prev, isOnline: false }));
    };
    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

    const checkConnectionSpeed = async () => {
      const connection = (navigator as any).connection;
      if (connection) {
        setState(prev => ({
          ...prev,
          isSlowConnection: connection.effectiveType === 'slow-2g' || connection.effectiveType === '2g'
        }));
      }
    };
    const interval = setInterval(checkConnectionSpeed, 120000);
    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
      clearInterval(interval);
    };
  }, []);

  const processQueue = useCallback(async () => { /* ... */ }, []);
  const enqueueOperation = useCallback((operation: () => Promise<void>, options?: any) => { /* ... */ }, []);
  const executeWithRetry = useCallback(async <T>(operation: () => Promise<T>, options?: any) => { /* ... */ }, []);

  return { ...state, enqueueOperation, executeWithRetry, queueLength: queueRef.current.length };
}

【文件7】src/components/ErrorBoundary.tsx - 错误边界组件（部分）
───────────────────────────────────────────────────────────────────────────────
import React, { Component, ErrorInfo, ReactNode } from 'react';
import { AlertCircle, RefreshCw, Home } from 'lucide-react';

interface Props { children: ReactNode; fallback?: ReactNode; onError?: (error: Error, errorInfo: ErrorInfo) => void; }
interface State { hasError: boolean; error: Error | null; errorInfo: ErrorInfo | null; }

export class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = { hasError: false, error: null, errorInfo: null };
  }

  static getDerivedStateFromError(error: Error): Partial<State> {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    this.setState({ errorInfo });
    if (this.props.onError) this.props.onError(error, errorInfo);
    console.error('ErrorBoundary caught an error:', error, errorInfo);
  }

  handleReset = () => this.setState({ hasError: false, error: null, errorInfo: null });
  handleGoHome = () => window.location.href = '/';
  handleReload = () => window.location.reload();

  render() {
    if (this.state.hasError) {
      if (this.props.fallback) return this.props.fallback;
      return (
        <div className="min-h-screen bg-gray-50 flex items-center justify-center p-4">
          <div className="bg-white rounded-2xl shadow-lg border border-gray-200 p-6 sm:p-8 max-w-md w-full">
            <div className="flex items-center gap-3 mb-4">
              <div className="w-12 h-12 bg-red-100 rounded-full flex items-center justify-center">
                <AlertCircle className="w-6 h-6 text-red-600" />
              </div>
              <div>
                <h2 className="text-lg font-semibold text-gray-900">页面出错了</h2>
                <p className="text-sm text-gray-500">抱歉，发生了意外错误</p>
              </div>
            </div>
            <div className="bg-gray-50 rounded-lg p-3 mb-4 overflow-auto max-h-32">
              <p className="text-xs text-gray-600 font-mono break-all">{this.state.error?.toString()}</p>
            </div>
            <div className="space-y-2">
              <button onClick={this.handleReset} className="w-full flex items-center justify-center gap-2 px-4 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors text-sm font-medium">
                <RefreshCw className="w-4 h-4" /> 重试
              </button>
              <div className="flex gap-2">
                <button onClick={this.handleGoHome} className="flex-1 flex items-center justify-center gap-2 px-4 py-2.5 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors text-sm font-medium">
                  <Home className="w-4 h-4" /> 返回首页
                </button>
                <button onClick={this.handleReload} className="flex-1 flex items-center justify-center gap-2 px-4 py-2.5 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors text-sm font-medium">
                  <RefreshCw className="w-4 h-4" /> 刷新页面
                </button>
              </div>
            </div>
          </div>
        </div>
      );
    }
    return this.props.children;
  }
}

═══════════════════════════════════════════════════════════════════════════════
                              源代码特征说明
═══════════════════════════════════════════════════════════════════════════════

1. 编程语言：TypeScript (.ts, .tsx)
2. 前端框架：React 18 + React Router v6
3. 状态管理：React Context + Hooks
4. 动画库：Framer Motion
5. 样式方案：TailwindCSS
6. 后端服务：Supabase (PostgreSQL)
7. 构建工具：Webpack 5

代码特点：
- 使用函数组件和React Hooks
- 类型安全的TypeScript开发
- 模块化设计，组件化架构
- 响应式设计，支持移动端
- 错误边界处理机制
- 实时数据同步

═══════════════════════════════════════════════════════════════════════════════
                         第 1 页 / 共 30 页（前30页）
═══════════════════════════════════════════════════════════════════════════════
