from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse from routers import auth, company, categories, products, product_certifications, product_media, product_packaging, membership, operation_log, contact, template, customer_relationship, member_level, r2_config, media, statistics from database import engine, Base, get_db from sqlalchemy.orm import Session import json import os from pathlib import Path from dotenv import load_dotenv from datetime import datetime, timedelta # 导入中间件 from middleware.trace import TraceMiddleware # 导入日志模块 from utils.logger import logger # 加载 .env 文件 load_dotenv() # 导入模板配置 from config.templates import DEFAULT_TEMPLATES # 导入会员等级配置 from config.member_levels import DEFAULT_MEMBER_LEVELS # 导入默认公司和用户配置 from config.default_companies import DEFAULT_COMPANIES, DEFAULT_USERS # 导入所有模型,确保它们被注册到Base from models.user import User from models.company import Company from models.category import Category from models.product import Product from models.membership import Membership from models.operation_log import OperationLog from models.contact import Contact from models.template import Template from models.customer_relationship import CustomerRelationship from models.member_level import MemberLevel from models.company_r2_config import CompanyR2Config from models.media import Media, MediaTag, MediaTagMapping, MediaDirectory from models.site_visit import SiteVisit from utils.auth import get_password_hash # 数据库表创建已在database.py中处理 app = FastAPI( title="外贸独立站 API", description="用于外贸独立站的后端 API", version="1.0.0" ) # 配置 CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], # 在生产环境中应该设置具体的前端域名 allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 添加 TraceMiddleware 中间件 app.add_middleware(TraceMiddleware) # 挂载静态文件目录(用于访问上传的图片) BASE_DIR = Path(__file__).parent IMAGES_DIR = BASE_DIR / "images" if IMAGES_DIR.exists(): app.mount("/images", StaticFiles(directory=str(IMAGES_DIR)), name="images") # 注册路由 # 注意:更具体的路由(如 /{product_number}/media)必须在较不具体的路由(如 /{product_number})之前注册 app.include_router(auth.router, prefix="/api/auth", tags=["认证"]) app.include_router(product_media.router, prefix="/api/products", tags=["产品媒体"]) app.include_router(product_certifications.router, prefix="/api/products", tags=["产品认证"]) app.include_router(product_packaging.router, prefix="/api/products", tags=["产品包装"]) app.include_router(products.router, prefix="/api/products", tags=["产品"]) app.include_router(company.router, prefix="/api/company", tags=["公司信息"]) app.include_router(categories.router, prefix="/api/categories", tags=["类目"]) app.include_router(membership.router, prefix="/api/membership", tags=["会员充值"]) app.include_router(operation_log.router, prefix="/api/operation-logs", tags=["操作日志"]) app.include_router(contact.router, prefix="/api/contact", tags=["联系信息管理"]) app.include_router(template.router, prefix="/api/templates", tags=["模板管理"]) app.include_router(customer_relationship.router, prefix="/api/customer-relationships", tags=["客户关系管理"]) app.include_router(member_level.router, prefix="/api/member-levels", tags=["会员等级管理"]) app.include_router(r2_config.router, prefix="/api/r2-config", tags=["R2 配置管理"]) app.include_router(media.router, prefix="/api/media", tags=["媒体素材管理"]) app.include_router(statistics.router, prefix="/api/statistics", tags=["统计指标"]) # 初始化超级管理员用户和默认类目 @app.on_event("startup") def startup_event(): try: db = next(get_db()) # 检查是否已有超级管理员 superadmin = db.query(User).filter(User.is_superadmin == True).first() if not superadmin: # 创建超级管理员 superadmin = User( username="admin", email="admin@mail.yomaton.com", password=get_password_hash("admin00"), is_superadmin=True, company_code="0000" ) db.add(superadmin) db.commit() logger.info("超级管理员已创建: username=admin, password=admin00") # 创建默认模板 for template_data in DEFAULT_TEMPLATES: # 转换features和regions列表为JSON字符串 template_data["features"] = json.dumps(template_data["features"], ensure_ascii=False) template_data["regions"] = json.dumps(template_data["regions"], ensure_ascii=False) existing_template = db.query(Template).filter(Template.key == template_data["key"]).first() if not existing_template: new_template = Template(**template_data) db.add(new_template) db.commit() logger.info("默认模板已创建") # 创建默认会员等级 for level_data in DEFAULT_MEMBER_LEVELS: existing_level = db.query(MemberLevel).filter(MemberLevel.level == level_data["level"]).first() if not existing_level: new_level = MemberLevel(**level_data) db.add(new_level) db.commit() logger.info("默认会员等级已创建") # 创建默认公司 for company_data in DEFAULT_COMPANIES: existing_company = db.query(Company).filter(Company.company_code == company_data["company_code"]).first() if not existing_company: new_company = Company(**company_data) db.add(new_company) db.commit() logger.info("默认公司已创建") # 创建默认用户和会员信息 for user_data in DEFAULT_USERS: existing_user = db.query(User).filter(User.username == user_data["username"]).first() if not existing_user: user_data_copy = user_data.copy() user_data_copy["password"] = get_password_hash(user_data_copy["password"]) new_user = User(**user_data_copy) db.add(new_user) db.flush() # 为用户创建默认会员信息 existing_membership = db.query(Membership).filter(Membership.company_code == user_data["company_code"]).first() if not existing_membership: new_membership = Membership( company_code = user_data["company_code"], level = 0, # 默认普通会员 start_date = datetime.now(), end_date = datetime.now() + timedelta(days=365) ) db.add(new_membership) db.commit() logger.info("默认用户和会员信息已创建") except Exception as e: logger.error(f"初始化数据时出错: {e}") @app.get("/") def read_root(): logger.info("访问根路径") return {"message": "欢迎使用外贸独立站 API"} @app.get("/health") def health_check(): logger.info("健康检查") return {"status": "healthy"} if __name__ == "__main__": import uvicorn logger.info("启动应用服务器") uvicorn.run(app, host="0.0.0.0", port=7860)