# 🚀 大型电商平台重构工作流 ## ThinkPHP 3.x → FastAPI + Ant Design Pro Vue + MySQL 8.0 --- ## 📋 项目概览 ### 当前系统分析 - **技术栈**: ThinkPHP 3.x + MySQL 5.7 + PHP 模板 - **规模**: 180+ 数据库表,10+ 业务模块,复杂订单系统 - **核心业务**: 电商订单管理、骑手配送、支付处理、会员系统、门店管理 - **复杂度**: 多租户架构、实时定位、多种支付方式、复杂订单状态机 ### 目标架构 - **后端**: FastAPI (Python 3.9+) + SQLAlchemy + Redis - **前端**: Ant Design Pro Vue (Vue 3 + TypeScript) - **数据库**: MySQL 8.0 优化版本 - **架构**: 模块化单体 → 微服务演进 - **基础设施**: Docker + Nginx + CI/CD --- ## 🎯 总体迁移策略 ### 核心原则 1. **零停机迁移**: 渐进式迁移,新旧系统并行运行 2. **数据完整性**: 金融级数据安全和一致性 3. **功能对等**: 所有现有功能必须完整保留 4. **渐进式实施**: 分阶段交付,降低风险 5. **性能优先**: 新系统性能必须显著优于旧系统 ### 技术风险控制 - **数据库双写**: 迁移期间确保数据同步 - **API网关**: 新旧系统平滑切换 - **监控告警**: 全链路性能监控 - **回滚机制**: 快速回退到旧系统能力 --- ## 📅 分阶段实施计划 ## 🏗️ 第一阶段:基础设施搭建 (1-3个月) ### 1.1 环境准备与基础设施 (2周) ```yaml 目标: 搭建开发和部署环境 关键交付: - Docker开发环境 - CI/CD流水线 - 数据库环境(新旧并行) - 监控和日志系统 ``` **具体任务清单:** - [ ] 设置Docker开发环境 (dev/staging/prod) - [ ] 配置GitLab CI/CD流水线 - [ ] 搭建MySQL 8.0集群并配置主从复制 - [ ] 设置Redis集群用于缓存和会话 - [ ] 配置ELK日志收集和监控系统 - [ ] 建立数据库双写同步机制 ### 1.2 数据库迁移设计与实施 (3周) ```yaml 目标: 设计优化数据库结构并制定迁移策略 关键交付: - 优化的MySQL 8.0数据库结构 - 数据迁移脚本和验证程序 - 双写同步机制 - 回滚方案 ``` **核心表结构重新设计:** ```sql -- 订单表优化设计 CREATE TABLE `orders` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `order_no` VARCHAR(32) UNIQUE NOT NULL, `merchant_id` BIGINT NOT NULL, `store_id` BIGINT NOT NULL, `customer_id` BIGINT, `rider_id` BIGINT, `order_type` TINYINT DEFAULT 1, `status` TINYINT NOT NULL DEFAULT 0, `payment_status` TINYINT NOT NULL DEFAULT 0, `original_amount` DECIMAL(12,2) NOT NULL, `discount_amount` DECIMAL(12,2) DEFAULT 0.00, `delivery_fee` DECIMAL(8,2) DEFAULT 0.00, `final_amount` DECIMAL(12,2) NOT NULL, `payment_method` TINYINT, `payment_details` JSON, `delivery_address` JSON, `items` JSON NOT NULL, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `completed_at` TIMESTAMP NULL, INDEX idx_merchant_store (merchant_id, store_id), INDEX idx_customer (customer_id), INDEX idx_rider (rider_id), INDEX idx_status_created (status, created_at), INDEX idx_order_no (order_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- 骑手表优化设计 CREATE TABLE `riders` ( `id` BIGINT PRIMARY KEY AUTO_INCREMENT, `merchant_id` BIGINT NOT NULL, `store_id` BIGINT NOT NULL, `name` VARCHAR(50) NOT NULL, `phone` VARCHAR(20) NOT NULL, `avatar_url` VARCHAR(255), `id_card` VARCHAR(18) UNIQUE, `id_card_front` VARCHAR(255), `id_card_back` VARCHAR(255), `health_cert` VARCHAR(255), `health_cert_expire` DATE, `work_status` TINYINT DEFAULT 0 COMMENT '0离线 1在线 2忙碌', `auth_status` TINYINT DEFAULT 0 COMMENT '0未认证 1认证中 2已认证 3认证失败', `current_location` POINT, `location_updated_at` TIMESTAMP NULL, `balance` DECIMAL(10,2) DEFAULT 0.00, `frozen_balance` DECIMAL(10,2) DEFAULT 0.00, `total_orders` INT DEFAULT 0, `completed_orders` INT DEFAULT 0, `rating` DECIMAL(3,2) DEFAULT 5.00, `on_time_rate` DECIMAL(5,2) DEFAULT 100.00, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `last_login_at` TIMESTAMP NULL, INDEX idx_merchant_store (merchant_id, store_id), INDEX idx_phone (phone), INDEX idx_work_status (work_status), INDEX idx_location (current_location), INDEX idx_rating (rating DESC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` **数据迁移策略:** - **双写阶段**: 新旧系统同时写入,确保数据一致性 - **验证阶段**: 定期对比新旧数据库数据差异 - **切换阶段**: 逐步切换读操作到新数据库 - **清理阶段**: 确认无误后清理旧数据库 ### 1.3 FastAPI项目架构设计 (2周) ```python # 项目结构 project_structure = """ fastapi_ecommerce/ ├── app/ │ ├── core/ │ │ ├── config.py # 配置管理 │ │ ├── security.py # 安全认证 │ │ ├── database.py # 数据库连接 │ │ └── middleware.py # 中间件 │ ├── schemas/ # Pydantic数据模型 │ │ ├── order.py │ │ ├── rider.py │ │ ├── store.py │ │ └── user.py │ ├── services/ # 业务逻辑层 │ │ ├── order_service.py │ │ ├── payment_service.py │ │ ├── rider_service.py │ │ └── notification_service.py │ ├── api/ # API路由 │ │ ├── v1/ │ │ │ ├── orders.py │ │ │ ├── riders.py │ │ │ ├── stores.py │ │ │ └── payments.py │ │ └── dependencies.py # 依赖注入 │ ├── models/ # SQLAlchemy模型 │ │ ├── base.py │ │ ├── order.py │ │ ├── rider.py │ │ └── store.py │ ├── utils/ # 工具函数 │ └── tests/ # 测试文件 ├── migrations/ # 数据库迁移文件 ├── scripts/ # 脚本文件 └── requirements.txt """ # 核心配置示例 from pydantic import BaseSettings class Settings(BaseSettings): # 数据库配置 DATABASE_URL: str = "mysql+asyncmy://user:pass@localhost/db" # Redis配置 REDIS_URL: str = "redis://localhost:6379" # JWT配置 SECRET_KEY: str = "your-secret-key" ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 # 支付配置 WECHAT_APP_ID: str WECHAT_MCH_ID: str ALIPAY_APP_ID: str class Config: env_file = ".env" ``` ### 1.4 身份认证与权限系统 (1周) ```python # JWT + RBAC权限控制 from fastapi import Depends, HTTPException from fastapi.security import HTTPBearer import jwt class AuthService: def create_access_token(self, data: dict): to_encode = data.copy() expire = datetime.utcnow() + timedelta(minutes=30) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt def verify_token(self, token: str): try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) user_id: str = payload.get("sub") if user_id is None: raise HTTPException(status_code=401, detail="Invalid token") return user_id except jwt.PyJWTError: raise HTTPException(status_code=401, detail="Invalid token") # 权限装饰器 def require_permission(permission: str): def decorator(func): async def wrapper(*args, **kwargs): user = kwargs.get('current_user') if not user.has_permission(permission): raise HTTPException(status_code=403, detail="Permission denied") return await func(*args, **kwargs) return wrapper return decorator ``` --- ## 🛒 第二阶段:核心业务系统迁移 (4-6个月) ### 2.1 订单管理系统重构 (4周) ```yaml 目标: 迁移核心订单管理功能 关键交付: - 订单CRUD操作 - 订单状态机 - 订单支付流程 - 订单退款流程 - 订单查询和统计 ``` **订单状态机设计:** ```python from enum import Enum from typing import Dict, List class OrderStatus(str, Enum): PENDING = "pending" # 待支付 PAID = "paid" # 已支付 PREPARING = "preparing" # 准备中 READY = "ready" # 待配送 PICKING = "picking" # 配送中 DELIVERED = "delivered" # 已送达 COMPLETED = "completed" # 已完成 CANCELLED = "cancelled" # 已取消 REFUNDED = "refunded" # 已退款 class OrderStateMachine: transitions = { OrderStatus.PENDING: [OrderStatus.PAID, OrderStatus.CANCELLED], OrderStatus.PAID: [OrderStatus.PREPARING, OrderStatus.REFUNDED], OrderStatus.PREPARING: [OrderStatus.READY, OrderStatus.CANCELLED], OrderStatus.READY: [OrderStatus.PICKING], OrderStatus.PICKING: [OrderStatus.DELIVERED, OrderStatus.READY], OrderStatus.DELIVERED: [OrderStatus.COMPLETED], OrderStatus.COMPLETED: [OrderStatus.REFUNDED], OrderStatus.CANCELLED: [], OrderStatus.REFUNDED: [] } def can_transition(self, from_status: OrderStatus, to_status: OrderStatus) -> bool: return to_status in self.transitions.get(from_status, []) def transition(self, current_status: OrderStatus, new_status: OrderStatus) -> bool: if self.can_transition(current_status, new_status): # 记录状态变更日志 # 触发相关业务逻辑 return True return False ``` **API设计:** ```python from fastapi import APIRouter, Depends, HTTPException from app.schemas.order import OrderCreate, OrderResponse, OrderUpdate from app.services.order_service import OrderService router = APIRouter(prefix="/api/v1/orders", tags=["orders"]) @router.post("/", response_model=OrderResponse) async def create_order( order_data: OrderCreate, current_user: User = Depends(get_current_user), order_service: OrderService = Depends() ): """创建新订单""" return await order_service.create_order(order_data, current_user.id) @router.get("/{order_id}", response_model=OrderResponse) async def get_order( order_id: int, current_user: User = Depends(get_current_user) ): """获取订单详情""" order = await order_service.get_order_by_id(order_id) if not order or order.user_id != current_user.id: raise HTTPException(status_code=404, detail="Order not found") return order @router.patch("/{order_id}/status") async def update_order_status( order_id: int, status_data: OrderUpdate, current_user: User = Depends(get_current_user) ): """更新订单状态""" return await order_service.update_order_status( order_id, status_data.status, current_user.id ) ``` ### 2.2 支付系统现代化 (3周) ```yaml 目标: 重构支付系统,支持多种支付方式 关键交付: - 微信支付集成 - 支付宝支付集成 - 组合支付支持 - 退款处理 - 支付回调处理 ``` **支付系统架构:** ```python from abc import ABC, abstractmethod from typing import Optional, Dict, Any class PaymentProvider(ABC): @abstractmethod async def create_payment(self, order_data: Dict[str, Any]) -> Dict[str, Any]: pass @abstractmethod async def verify_payment(self, payment_data: Dict[str, Any]) -> bool: pass @abstractmethod async def refund_payment(self, payment_id: str, amount: float) -> Dict[str, Any]: pass class WechatPayProvider(PaymentProvider): def __init__(self, app_id: str, mch_id: str, api_key: str): self.app_id = app_id self.mch_id = mch_id self.api_key = api_key async def create_payment(self, order_data: Dict[str, Any]) -> Dict[str, Any]: # 微信支付统一下单接口 # 返回支付参数供客户端调用 pass async def verify_payment(self, payment_data: Dict[str, Any]) -> bool: # 验证微信支付回调 pass class AlipayProvider(PaymentProvider): def __init__(self, app_id: str, private_key: str, public_key: str): self.app_id = app_id self.private_key = private_key self.public_key = public_key async def create_payment(self, order_data: Dict[str, Any]) -> Dict[str, Any]: # 支付宝支付接口 pass async def verify_payment(self, payment_data: Dict[str, Any]) -> bool: # 验证支付宝回调 pass class PaymentService: def __init__(self): self.providers = { "wechat": WechatPayProvider(), "alipay": AlipayProvider(), "cash": CashPaymentProvider(), "balance": BalancePaymentProvider() } async def process_payment(self, order_id: int, payment_method: str, amount: float): provider = self.providers.get(payment_method) if not provider: raise ValueError(f"Unsupported payment method: {payment_method}") return await provider.create_payment({ "order_id": order_id, "amount": amount }) ``` ### 2.3 门店管理系统迁移 (2周) ```python # 门店配置管理 from app.schemas.store import StoreConfig, StoreCreate, StoreUpdate @router.get("/stores/{store_id}/config") async def get_store_config(store_id: int): """获取门店配置""" config = await store_service.get_config(store_id) return config @router.put("/stores/{store_id}/config") async def update_store_config( store_id: int, config: StoreConfig, current_user: User = Depends(get_current_merchant_user) ): """更新门店配置""" return await store_service.update_config(store_id, config) @router.get("/stores/{store_id}/inventory") async def get_store_inventory(store_id: int): """获取门店库存""" return await store_service.get_inventory(store_id) @router.post("/stores/{store_id}/delivery-areas") async def update_delivery_areas( store_id: int, areas: List[DeliveryArea], current_user: User = Depends(get_current_merchant_user) ): """更新门店配送范围""" return await store_service.update_delivery_areas(store_id, areas) ``` --- ## 🏍️ 第三阶段:高级功能实现 (7-9个月) ### 3.1 骑手管理与实时定位系统 (4周) ```yaml 目标: 实现骑手管理和实时定位追踪 关键交付: - 骑手注册认证 - 实时位置上传 - 订单智能分配 - 配送路径优化 - 绩效统计系统 ``` **实时定位系统:** ```python from fastapi import WebSocket, WebSocketDisconnect from typing import List, Dict import asyncio import json class LocationManager: def __init__(self): self.active_connections: Dict[int, WebSocket] = {} self.rider_locations: Dict[int, Dict] = {} async def connect_rider(self, websocket: WebSocket, rider_id: int): await websocket.accept() self.active_connections[rider_id] = websocket async def disconnect_rider(self, rider_id: int): if rider_id in self.active_connections: del self.active_connections[rider_id] if rider_id in self.rider_locations: del self.rider_locations[rider_id] async def update_location(self, rider_id: int, location: Dict): self.rider_locations[rider_id] = { **location, 'updated_at': datetime.utcnow() } # 广播给相关订单用户 await self.broadcast_location_update(rider_id, location) async def get_nearby_riders(self, lat: float, lng: float, radius: float = 5.0): """获取附近骑手""" nearby_riders = [] for rider_id, location_data in self.rider_locations.items(): rider_lat = location_data['latitude'] rider_lng = location_data['longitude'] distance = self.calculate_distance(lat, lng, rider_lat, rider_lng) if distance <= radius: nearby_riders.append({ 'rider_id': rider_id, 'distance': distance, 'location': location_data }) return sorted(nearby_riders, key=lambda x: x['distance']) def calculate_distance(self, lat1: float, lng1: float, lat2: float, lng2: float) -> float: """计算两点间距离(公里)""" from math import radians, cos, sin, asin, sqrt # 转换为弧度 lat1, lng1, lat2, lng2 = map(radians, [lat1, lng1, lat2, lng2]) # haversine公式 dlat = lat2 - lat1 dlng = lng2 - lng1 a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlng/2)**2 c = 2 * asin(sqrt(a)) r = 6371 # 地球半径(公里) return c * r # WebSocket定位上传 @router.websocket("/ws/rider/{rider_id}/location") async def location_websocket(websocket: WebSocket, rider_id: int): await location_manager.connect_rider(websocket, rider_id) try: while True: data = await websocket.receive_text() location_data = json.loads(data) # 验证位置数据格式 if 'latitude' in location_data and 'longitude' in location_data: await location_manager.update_location(rider_id, location_data) except WebSocketDisconnect: await location_manager.disconnect_rider(rider_id) ``` **智能订单分配算法:** ```python from typing import List, Tuple import asyncio class OrderDispatcher: def __init__(self, location_manager: LocationManager): self.location_manager = location_manager async def dispatch_order(self, order_id: int, store_location: Dict) -> Optional[int]: """智能分配订单给骑手""" # 获取订单详情 order = await self.get_order(order_id) if not order: return None # 获取附近骑手 nearby_riders = await self.location_manager.get_nearby_riders( store_location['latitude'], store_location['longitude'], radius=10.0 ) # 筛选可用骑手 available_riders = await self.filter_available_riders(nearby_riders) if not available_riders: return None # 综合评分算法 best_rider = await self.select_best_rider(available_riders, order) if best_rider: # 分配订单 await self.assign_order_to_rider(order_id, best_rider['rider_id']) return best_rider['rider_id'] return None async def filter_available_riders(self, riders: List[Dict]) -> List[Dict]: """筛选可用骑手""" available_riders = [] for rider in riders: # 检查骑手工作状态 if rider['work_status'] != 1: # 1为在线 continue # 检查当前订单数量 if rider['current_orders'] >= 3: # 最多同时接3单 continue # 检查评分 if rider['rating'] < 4.0: # 评分低于4.0不分配 continue available_riders.append(rider) return available_riders async def select_best_rider(self, riders: List[Dict], order: Dict) -> Optional[Dict]: """选择最佳骑手""" if not riders: return None def calculate_score(rider: Dict) -> float: distance_score = 10 / (rider['distance'] + 0.1) # 距离越近分数越高 rating_score = rider['rating'] * 2 # 评分权重 orders_score = rider['completed_orders'] * 0.01 # 经验权重 on_time_score = rider['on_time_rate'] * 0.1 # 准时率权重 return distance_score + rating_score + orders_score + on_time_score # 计算每个骑手的综合评分 scored_riders = [] for rider in riders: score = calculate_score(rider) scored_riders.append({**rider, 'dispatch_score': score}) # 返回评分最高的骑手 return max(scored_riders, key=lambda x: x['dispatch_score']) ``` ### 3.2 配送系统与路径优化 (3周) ```python from typing import List, Tuple import asyncio import requests class DeliveryService: def __init__(self): self.map_service = MapService() # 地图服务(高德/百度) async def plan_delivery_route(self, orders: List[Dict], start_location: Dict) -> Dict: """规划最优配送路径""" if not orders: return {"route": [], "total_distance": 0, "estimated_time": 0} # 构建途经点 waypoints = [ (order['delivery_address']['latitude'], order['delivery_address']['longitude']) for order in orders ] # 调用地图API规划路径 route_result = await self.map_service.get_optimal_route( start=(start_location['latitude'], start_location['longitude']), waypoints=waypoints ) return { "route": route_result['route'], "total_distance": route_result['distance'], "estimated_time": route_result['duration'], "orders_sequence": self.optimize_order_sequence(orders, route_result['route']) } def optimize_order_sequence(self, orders: List[Dict], route: List[Dict]) -> List[int]: """根据路径优化订单配送顺序""" # 简单实现:按照路径顺序排列订单 # 实际可考虑更多因素:配送时间窗口、优先级等 order_sequence = [] for point in route[1:]: # 排除起点 # 找到最近的订单 nearest_order = min( orders, key=lambda o: self.calculate_distance( point['latitude'], point['longitude'], o['delivery_address']['latitude'], o['delivery_address']['longitude'] ) ) if nearest_order not in order_sequence: order_sequence.append(nearest_order) return [order['id'] for order in order_sequence] async def update_delivery_status(self, order_id: int, status: str, location: Dict = None): """更新配送状态""" # 更新订单状态 await self.order_service.update_status(order_id, status) # 更新骑手位置 if location: await self.location_manager.update_location( self.get_rider_id_by_order(order_id), location ) # 发送通知给用户 if status in ['picking', 'delivering', 'delivered']: await self.notification_service.send_delivery_update( order_id, status ) class MapService: def __init__(self): self.api_key = "your_map_api_key" self.base_url = "https://restapi.amap.com/v3" async def get_optimal_route(self, start: Tuple[float, float], waypoints: List[Tuple[float, float]]) -> Dict: """调用高德地图API获取最优路径""" url = f"{self.base_url}/direction/driving" params = { 'key': self.api_key, 'origin': f"{start[1]},{start[0]}", # 经度,纬度 'destination': f"{waypoints[-1][1]},{waypoints[-1][0]}", 'waypoints': ';'.join([f"{wp[1]},{wp[0]}" for wp in waypoints[:-1]]), 'strategy': 1, # 距离优先策略 } async with aiohttp.ClientSession() as session: async with session.get(url, params=params) as response: data = await response.json() if data.get('status') == '1' and data.get('count') != '0': route = data['route']['paths'][0] return { 'distance': int(route['distance']) / 1000, # 转换为公里 'duration': int(route['duration']) // 60, # 转换为分钟 'route': self.parse_route_steps(route['steps']) } else: raise Exception("Failed to get route from map API") def parse_route_steps(self, steps: List[Dict]) -> List[Dict]: """解析路径步骤""" route = [] for step in steps: instruction = step['instruction'] distance = int(step['distance']) / 1000 # 转换为公里 duration = int(step['duration']) // 60 # 转换为分钟 # 解析坐标点 polyline = step['polyline'] points = self.decode_polyline(polyline) route.append({ 'instruction': instruction, 'distance': distance, 'duration': duration, 'coordinates': points }) return route ``` --- ## 💎 第四阶段:系统优化与完善 (10-12个月) ### 4.1 性能优化与监控 (3周) ```yaml 目标: 全面优化系统性能和建立监控体系 关键交付: - 数据库查询优化 - Redis缓存策略 - API响应时间优化 - 全链路监控 - 压力测试与调优 ``` **缓存策略设计:** ```python from functools import wraps from typing import Any, Optional import redis import json import hashlib class CacheManager: def __init__(self, redis_client: redis.Redis): self.redis = redis_client self.default_ttl = 3600 # 1小时 def cache(self, key_prefix: str, ttl: int = None): """缓存装饰器""" def decorator(func): @wraps(func) async def wrapper(*args, **kwargs): # 生成缓存键 cache_key = self.generate_cache_key(key_prefix, *args, **kwargs) # 尝试从缓存获取 cached_result = await self.get(cache_key) if cached_result is not None: return cached_result # 执行原函数 result = await func(*args, **kwargs) # 存储到缓存 await self.set(cache_key, result, ttl or self.default_ttl) return result return wrapper return decorator def generate_cache_key(self, prefix: str, *args, **kwargs) -> str: """生成缓存键""" key_data = { 'args': args, 'kwargs': sorted(kwargs.items()) } key_hash = hashlib.md5(json.dumps(key_data, sort_keys=True).encode()).hexdigest() return f"{prefix}:{key_hash}" async def get(self, key: str) -> Optional[Any]: """获取缓存""" try: data = await self.redis.get(key) if data: return json.loads(data) except Exception as e: print(f"Cache get error: {e}") return None async def set(self, key: str, value: Any, ttl: int) -> bool: """设置缓存""" try: data = json.dumps(value, default=str) await self.redis.setex(key, ttl, data) return True except Exception as e: print(f"Cache set error: {e}") return False # 使用示例 cache_manager = CacheManager(redis_client) @cache_manager.cache("order_details", ttl=1800) # 30分钟 async def get_order_details(order_id: int): """获取订单详情(带缓存)""" order = await order_repository.get_by_id(order_id) if order: # 加载关联数据 order.items = await order_item_repository.get_by_order_id(order_id) order.payments = await payment_repository.get_by_order_id(order_id) return order @cache_manager.cache("rider_stats", ttl=300) # 5分钟 async def get_rider_statistics(rider_id: int, date_range: str): """获取骑手统计数据(带缓存)""" return await rider_repository.get_statistics(rider_id, date_range) ``` **性能监控:** ```python from prometheus_client import Counter, Histogram, Gauge import time from functools import wraps # Prometheus指标 REQUEST_COUNT = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint', 'status']) REQUEST_DURATION = Histogram('http_request_duration_seconds', 'HTTP request duration') ACTIVE_CONNECTIONS = Gauge('active_connections', 'Active connections') def monitor_requests(func): """请求监控装饰器""" @wraps(func) async def wrapper(*args, **kwargs): start_time = time.time() try: result = await func(*args, **kwargs) status = 'success' return result except Exception as e: status = 'error' raise finally: duration = time.time() - start_time REQUEST_DURATION.observe(duration) REQUEST_COUNT.labels( method=kwargs.get('method', 'unknown'), endpoint=kwargs.get('endpoint', func.__name__), status=status ).inc() return wrapper # 中间件监控 @app.middleware("http") async def monitoring_middleware(request: Request, call_next): start_time = time.time() # 增加活跃连接数 ACTIVE_CONNECTIONS.inc() try: response = await call_next(request) # 记录请求指标 duration = time.time() - start_time REQUEST_DURATION.observe(duration) REQUEST_COUNT.labels( method=request.method, endpoint=request.url.path, status='success' ).inc() # 添加响应头 response.headers["X-Process-Time"] = str(duration) return response except Exception as e: REQUEST_COUNT.labels( method=request.method, endpoint=request.url.path, status='error' ).inc() raise finally: # 减少活跃连接数 ACTIVE_CONNECTIONS.dec() ``` ### 4.2 Ant Design Pro Vue前端开发 (6-8周) **前端项目结构:** ``` frontend/ ├── src/ │ ├── components/ # 通用组件 │ │ ├── ProTable/ │ │ ├── ProForm/ │ │ └── Charts/ │ ├── pages/ # 页面组件 │ │ ├── order/ │ │ │ ├── list.vue │ │ │ ├── detail.vue │ │ │ └── create.vue │ │ ├── rider/ │ │ ├── store/ │ │ └── dashboard/ │ ├── services/ # API服务 │ │ ├── order.ts │ │ ├── rider.ts │ │ └── user.ts │ ├── stores/ # Pinia状态管理 │ │ ├── order.ts │ │ ├── user.ts │ │ └── app.ts │ ├── utils/ # 工具函数 │ ├── types/ # TypeScript类型定义 │ └── layouts/ # 布局组件 ├── public/ ├── package.json └── vite.config.ts ``` **核心页面组件示例:** ```vue ``` --- ## 🧪 测试策略与质量保证 ### 测试框架设计 ```python # pytest配置 import pytest import asyncio from httpx import AsyncClient from app.main import app @pytest.fixture async def client(): async with AsyncClient(app=app, base_url="http://test") as ac: yield ac @pytest.fixture async def test_user_token(): # 创建测试用户并返回JWT token user_data = { "phone": "13800138000", "password": "test123456" } # ...创建用户逻辑 return "test_jwt_token" # 订单API测试 @pytest.mark.asyncio async def test_create_order(client: AsyncClient, test_user_token: str): order_data = { "store_id": 1, "items": [ {"goods_id": 1, "quantity": 2, "price": 12.50}, {"goods_id": 2, "quantity": 1, "price": 8.00} ], "delivery_address": { "address": "测试地址", "latitude": 39.9042, "longitude": 116.4074, "contact_phone": "13800138000" } } response = await client.post( "/api/v1/orders", json=order_data, headers={"Authorization": f"Bearer {test_user_token}"} ) assert response.status_code == 200 data = response.json() assert data["status"] == 1 assert "order_id" in data["data"] assert data["data"]["final_amount"] == 33.00 # 支付测试 @pytest.mark.asyncio async def test_payment_process(client: AsyncClient, test_user_token: str): # 首先创建订单 order_response = await test_create_order(client, test_user_token) order_id = order_response.json()["data"]["order_id"] # 测试支付 payment_data = { "order_id": order_id, "payment_method": "wechat", "amount": 33.00 } response = await client.post( "/api/v1/payments", json=payment_data, headers={"Authorization": f"Bearer {test_user_token}"} ) assert response.status_code == 200 data = response.json() assert data["status"] == 1 assert "payment_params" in data["data"] ``` --- ## 📊 性能指标与监控 ### 关键性能指标 ```yaml 系统性能目标: API响应时间: < 200ms (P95) 数据库查询时间: < 100ms (P95) 系统可用性: > 99.9% 并发用户数: 10,000+ 订单处理能力: 1,000 TPS 业务监控指标: 订单创建成功率: > 99.5% 支付成功率: > 98% 配送准时率: > 95% 骑手接单响应时间: < 30秒 ``` --- ## 🔧 部署与运维 ### Docker容器化 ```dockerfile # FastAPI后端Dockerfile FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] # Vue前端Dockerfile FROM node:16-alpine as build WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/nginx.conf EXPOSE 80 ``` ### Docker Compose配置 ```yaml version: '3.8' services: app: build: . ports: - "8000:8000" environment: - DATABASE_URL=mysql+asyncmy://user:password@db:3306/ecommerce - REDIS_URL=redis://redis:6379 depends_on: - db - redis volumes: - ./logs:/app/logs db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: ecommerce MYSQL_USER: user MYSQL_PASSWORD: password volumes: - mysql_data:/var/lib/mysql - ./init.sql:/docker-entrypoint-initdb.d/init.sql ports: - "3306:3306" redis: image: redis:6-alpine ports: - "6379:6379" volumes: - redis_data:/data nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf - ./ssl:/etc/nginx/ssl depends_on: - app volumes: mysql_data: redis_data: ``` --- ## ⚠️ 风险控制与应急预案 ### 数据安全 - **数据加密**: 敏感数据AES加密存储 - **传输安全**: HTTPS/TLS 1.3加密 - **访问控制**: 细粒度权限管理 - **审计日志**: 全链路操作审计 ### 系统稳定性 - **熔断机制**: 防止雪崩效应 - **限流控制**: API请求频率限制 - **降级策略**: 核心功能优先保证 - **备份方案**: 实时备份和快速恢复 ### 迁移风险 - **灰度发布**: 逐步切换流量 - **监控告警**: 实时系统健康监控 - **回滚预案**: 快速回退到旧系统 - **数据校验**: 新旧系统数据一致性检查 --- ## 📈 项目总结 ### 预期收益 1. **性能提升**: API响应时间提升60%+,系统吞吐量提升300%+ 2. **开发效率**: 现代化开发框架,代码质量和维护性大幅提升 3. **用户体验**: 实时功能、更好的UI交互、更快的页面加载 4. **运维效率**: 容器化部署、自动化运维、完善监控体系 5. **扩展性**: 微服务架构,支持业务快速迭代和横向扩展 ### 技术债务清理 - ✅ 移除ThinkPHP 3.x过时框架 - ✅ 升级到现代化技术栈 - ✅ 重构复杂业务逻辑 - ✅ 建立完善测试体系 - ✅ 实施DevOps最佳实践 这个重构计划将彻底现代化电商平台的技术架构,为未来的业务发展奠定坚实基础。