iloom-flatten/outputs/程序鉴别材料-源代码前30页.txt

468 lines
20 KiB
Plaintext
Raw Permalink Normal View History

═══════════════════════════════════════════════════════════════════════════════
程序鉴别材料 - 源代码前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页
═══════════════════════════════════════════════════════════════════════════════