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

468 lines
20 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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