新增上传图片的接口
This commit is contained in:
parent
93fb0fe4e9
commit
0afdca5805
@ -9,7 +9,10 @@ from app.models.order import (
|
||||
OrderPackageInfo,
|
||||
generate_order_id,
|
||||
OrderPriceCalculateRequest,
|
||||
OrderPriceInfo
|
||||
OrderPriceInfo,
|
||||
OrderStatus,
|
||||
OrderCancel,
|
||||
OrderComplete
|
||||
)
|
||||
from app.models.database import get_db
|
||||
from app.api.deps import get_current_user
|
||||
@ -182,3 +185,82 @@ async def calculate_order_price(
|
||||
)
|
||||
|
||||
return success_response(data=price_info)
|
||||
|
||||
@router.post("/{orderid}/cancel", response_model=ResponseModel)
|
||||
async def cancel_order(
|
||||
orderid: str,
|
||||
cancel_data: OrderCancel,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: UserDB = Depends(get_current_user)
|
||||
):
|
||||
"""取消订单"""
|
||||
# 查询订单
|
||||
order = db.query(ShippingOrderDB).filter(
|
||||
ShippingOrderDB.orderid == orderid,
|
||||
ShippingOrderDB.userid == current_user.userid
|
||||
).first()
|
||||
|
||||
if not order:
|
||||
return error_response(code=404, message="订单不存在")
|
||||
|
||||
# 检查订单状态是否可取消
|
||||
if order.status not in [OrderStatus.PENDING, OrderStatus.ACCEPTED]:
|
||||
return error_response(code=400, message="当前订单状态不可取消")
|
||||
|
||||
try:
|
||||
# 更新订单状态和取消原因
|
||||
order.status = OrderStatus.CANCELLED
|
||||
order.cancel_reason = cancel_data.reason
|
||||
|
||||
# 如果使用了优惠券,返还优惠券
|
||||
if order.coupon_id:
|
||||
coupon = db.query(UserCouponDB).filter(
|
||||
UserCouponDB.id == order.coupon_id
|
||||
).first()
|
||||
if coupon:
|
||||
coupon.status = CouponStatus.UNUSED
|
||||
|
||||
db.commit()
|
||||
return success_response(
|
||||
message="订单取消成功",
|
||||
data=OrderInfo.model_validate(order)
|
||||
)
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(code=500, message=f"取消订单失败: {str(e)}")
|
||||
|
||||
@router.post("/{orderid}/complete", response_model=ResponseModel)
|
||||
async def complete_order(
|
||||
orderid: str,
|
||||
complete_data: OrderComplete,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: UserDB = Depends(get_current_user)
|
||||
):
|
||||
"""完成订单"""
|
||||
# 查询订单
|
||||
order = db.query(ShippingOrderDB).filter(
|
||||
ShippingOrderDB.orderid == orderid,
|
||||
ShippingOrderDB.userid == current_user.userid
|
||||
).first()
|
||||
|
||||
if not order:
|
||||
return error_response(code=404, message="订单不存在")
|
||||
|
||||
# 检查订单状态
|
||||
if order.status != OrderStatus.ACCEPTED:
|
||||
return error_response(code=400, message="只有已接单的订单才能标记为完成")
|
||||
|
||||
try:
|
||||
# 更新订单状态和完成图片
|
||||
order.status = OrderStatus.COMPLETED
|
||||
if complete_data.images:
|
||||
order.complete_images = ",".join(complete_data.images)
|
||||
|
||||
db.commit()
|
||||
return success_response(
|
||||
message="订单已完成",
|
||||
data=OrderInfo.model_validate(order)
|
||||
)
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
return error_response(code=500, message=f"完成订单失败: {str(e)}")
|
||||
64
app/api/endpoints/upload.py
Normal file
64
app/api/endpoints/upload.py
Normal file
@ -0,0 +1,64 @@
|
||||
from fastapi import APIRouter, UploadFile, File, Depends
|
||||
from typing import List
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from app.core.cos import cos_client
|
||||
from app.core.config import settings
|
||||
from app.models.upload import UploadResponse, MultiUploadResponse
|
||||
from app.core.response import success_response, error_response, ResponseModel
|
||||
from app.api.deps import get_current_user
|
||||
from app.models.user import UserDB
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
async def upload_to_cos(file: UploadFile) -> str:
|
||||
"""上传文件到腾讯云COS"""
|
||||
# 生成唯一文件名
|
||||
ext = file.filename.split('.')[-1] if '.' in file.filename else ''
|
||||
filename = f"{datetime.now().strftime('%Y%m%d')}/{uuid.uuid4()}.{ext}"
|
||||
|
||||
# 上传文件
|
||||
cos_client.put_object(
|
||||
Bucket=settings.COS_BUCKET,
|
||||
Body=await file.read(),
|
||||
Key=filename,
|
||||
ContentType=file.content_type
|
||||
)
|
||||
|
||||
# 返回文件URL
|
||||
return f"{settings.COS_BASE_URL}/{filename}"
|
||||
|
||||
@router.post("/image", response_model=ResponseModel)
|
||||
async def upload_image(
|
||||
file: UploadFile = File(...),
|
||||
current_user: UserDB = Depends(get_current_user)
|
||||
):
|
||||
"""上传单张图片"""
|
||||
if not file.content_type.startswith('image/'):
|
||||
return error_response(code=400, message="只能上传图片文件")
|
||||
|
||||
try:
|
||||
url = await upload_to_cos(file)
|
||||
return success_response(data=UploadResponse(url=url))
|
||||
except Exception as e:
|
||||
return error_response(code=500, message=f"上传失败: {str(e)}")
|
||||
|
||||
@router.post("/images", response_model=ResponseModel)
|
||||
async def upload_images(
|
||||
files: List[UploadFile] = File(...),
|
||||
current_user: UserDB = Depends(get_current_user)
|
||||
):
|
||||
"""上传多张图片"""
|
||||
if len(files) > 5:
|
||||
return error_response(code=400, message="最多同时上传5张图片")
|
||||
|
||||
urls = []
|
||||
try:
|
||||
for file in files:
|
||||
if not file.content_type.startswith('image/'):
|
||||
return error_response(code=400, message="只能上传图片文件")
|
||||
url = await upload_to_cos(file)
|
||||
urls.append(url)
|
||||
return success_response(data=MultiUploadResponse(urls=urls))
|
||||
except Exception as e:
|
||||
return error_response(code=500, message=f"上传失败: {str(e)}")
|
||||
@ -37,6 +37,13 @@ class Settings(BaseSettings):
|
||||
def SQLALCHEMY_DATABASE_URL(self) -> str:
|
||||
return f"mysql+pymysql://{self.MYSQL_USER}:{self.MYSQL_PASSWORD}@{self.MYSQL_HOST}:{self.MYSQL_PORT}/{self.MYSQL_DB}?charset=utf8mb4"
|
||||
|
||||
# 腾讯云 COS 配置
|
||||
COS_SECRET_ID: str = "AKIDxnbGj281iHtKallqqzvlV5YxBCrPltnS"
|
||||
COS_SECRET_KEY: str = "ta6PXTMBsX7dzA7IN6uYUFn8F9uTovoU"
|
||||
COS_REGION: str = "ap-chengdu"
|
||||
COS_BUCKET: str = "dman-1311994147"
|
||||
COS_BASE_URL: str = "dman-1311994147.cos.ap-chengdu.myqcloud.com"
|
||||
|
||||
class Config:
|
||||
case_sensitive = True
|
||||
|
||||
|
||||
15
app/core/cos.py
Normal file
15
app/core/cos.py
Normal file
@ -0,0 +1,15 @@
|
||||
from qcloud_cos import CosConfig, CosS3Client
|
||||
from app.core.config import settings
|
||||
import sys
|
||||
import logging
|
||||
|
||||
# 正常情况日志级别使用INFO,需要定位时可以修改为DEBUG,此时SDK会打印和服务端的通信信息
|
||||
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
|
||||
|
||||
cos_config = CosConfig(
|
||||
Region=settings.COS_REGION,
|
||||
SecretId=settings.COS_SECRET_ID,
|
||||
SecretKey=settings.COS_SECRET_KEY
|
||||
)
|
||||
|
||||
cos_client = CosS3Client(cos_config)
|
||||
@ -1,6 +1,6 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from app.api.endpoints import user, address, community, station, order, coupon, community_building
|
||||
from app.api.endpoints import user, address, community, station, order, coupon, community_building, upload
|
||||
from app.models.database import Base, engine
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
@ -33,6 +33,7 @@ app.include_router(community_building.router, prefix="/api/community/building",
|
||||
app.include_router(station.router, prefix="/api/station", tags=["驿站"])
|
||||
app.include_router(order.router, prefix="/api/order", tags=["订单"])
|
||||
app.include_router(coupon.router, prefix="/api/coupon", tags=["优惠券"])
|
||||
app.include_router(upload.router, prefix="/api/upload", tags=["文件上传"])
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey
|
||||
from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum
|
||||
from sqlalchemy.sql import func
|
||||
from pydantic import BaseModel, Field
|
||||
from .database import Base
|
||||
import enum
|
||||
|
||||
class OrderStatus(str, enum.Enum):
|
||||
PENDING = "pending"
|
||||
ACCEPTED = "accepted"
|
||||
UNPAID = "unpaid"
|
||||
COMPLETED = "completed"
|
||||
CANCELLED = "cancelled"
|
||||
|
||||
# 数据库模型
|
||||
class ShippingOrderDB(Base):
|
||||
@ -17,6 +25,9 @@ class ShippingOrderDB(Base):
|
||||
coupon_discount_amount = Column(Float, default=0)
|
||||
coupon_id = Column(Integer, ForeignKey("user_coupons.id"), nullable=True)
|
||||
final_amount = Column(Float, nullable=False)
|
||||
status = Column(Enum(OrderStatus), nullable=False, default=OrderStatus.PENDING)
|
||||
cancel_reason = Column(String(200), nullable=True) # 取消原因
|
||||
complete_images = Column(String(1000), nullable=True) # 完成订单的图片URL,多个URL用逗号分隔
|
||||
create_time = Column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
class ShippingOrderPackageDB(Base):
|
||||
@ -49,8 +60,16 @@ class OrderInfo(BaseModel):
|
||||
coupon_discount_amount: float
|
||||
coupon_id: Optional[int]
|
||||
final_amount: float
|
||||
status: OrderStatus
|
||||
complete_images: Optional[List[str]] = None
|
||||
create_time: datetime
|
||||
|
||||
def __init__(self, **data):
|
||||
super().__init__(**data)
|
||||
# 将逗号分隔的图片URL字符串转换为列表
|
||||
if self.complete_images and isinstance(self.complete_images, str):
|
||||
self.complete_images = self.complete_images.split(",")
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
@ -82,3 +101,11 @@ class OrderPriceInfo(BaseModel):
|
||||
coupon_discount_amount: float
|
||||
coupon_id: Optional[int] = None
|
||||
final_amount: float
|
||||
|
||||
# 添加取消订单请求模型
|
||||
class OrderCancel(BaseModel):
|
||||
reason: str = Field(..., max_length=200, description="取消原因")
|
||||
|
||||
# 完成订单请求模型
|
||||
class OrderComplete(BaseModel):
|
||||
images: Optional[List[str]] = Field(None, max_items=5) # 最多5张图片,可选
|
||||
8
app/models/upload.py
Normal file
8
app/models/upload.py
Normal file
@ -0,0 +1,8 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import List
|
||||
|
||||
class UploadResponse(BaseModel):
|
||||
url: str
|
||||
|
||||
class MultiUploadResponse(BaseModel):
|
||||
urls: List[str]
|
||||
@ -10,3 +10,4 @@ redis==5.0.1
|
||||
pymysql==1.1.0
|
||||
SQLAlchemy==2.0.27
|
||||
unisms
|
||||
cos-python-sdk-v5==1.9.25
|
||||
Loading…
Reference in New Issue
Block a user