商品增加相关字段。

This commit is contained in:
aaron 2025-03-21 11:33:10 +08:00
parent ba3e00aab6
commit 03bc65e551
7 changed files with 332 additions and 7 deletions

View File

@ -9,15 +9,165 @@ from app.models.merchant import (
MerchantInfo) MerchantInfo)
from app.models.merchant_category import MerchantCategoryDB from app.models.merchant_category import MerchantCategoryDB
from app.models.database import get_db from app.models.database import get_db
from app.api.deps import get_admin_user from app.api.deps import get_admin_user, get_current_user
from app.models.user import UserDB from app.models.user import UserDB
from app.core.response import success_response, error_response, ResponseModel from app.core.response import success_response, error_response, ResponseModel
from app.models.merchant_pay_order import MerchantPayOrderDB from app.models.merchant_pay_order import MerchantPayOrderDB
from sqlalchemy.sql import func, desc from sqlalchemy.sql import func, desc
from app.models.merchant_product import MerchantProductDB, ProductStatus from app.models.merchant_product import MerchantProductDB, ProductStatus
from app.models.merchant import MerchantStatus, MerchantApply
from app.models.merchant_auth import MerchantAuthDB, MerchantAuthInfo
router = APIRouter() router = APIRouter()
@router.get("/apply", response_model=ResponseModel)
async def get_merchant_apply(
db: Session = Depends(get_db),
user: UserDB = Depends(get_current_user)
):
"""获取商家申请信息"""
merchant = db.query(MerchantDB).filter(MerchantDB.user_id == user.userid).first()
if not merchant:
return error_response(code=404, message="商家申请信息不存在")
auth = db.query(MerchantAuthDB).filter(MerchantAuthDB.merchant_id == merchant.id).first()
return success_response(data={
"merchant": MerchantInfo.model_validate(merchant),
"auth": MerchantAuthInfo.model_validate(auth)
})
@router.put("/apply", response_model=ResponseModel)
async def update_merchant_apply(
apply: MerchantApply,
db: Session = Depends(get_db),
user: UserDB = Depends(get_current_user)
):
"""更新商家申请信息"""
merchant = db.query(MerchantDB).filter(MerchantDB.user_id == user.userid).first()
if not merchant:
return error_response(code=404, message="商家不存在")
merchant.name = apply.name
merchant.business_hours = apply.business_hours
merchant.address = apply.address
merchant.longitude = apply.longitude
merchant.latitude = apply.latitude
merchant.phone = apply.phone
merchant.brand_image_url = apply.brand_image_url
merchant.category_id = apply.category_id
merchant.pay_share_rate = apply.pay_share_rate
auth = db.query(MerchantAuthDB).filter(MerchantAuthDB.merchant_id == merchant.id).first()
if auth:
auth.license_image_url = apply.license_image_url
auth.id_front_url = apply.id_front_url
auth.id_back_url = apply.id_back_url
db.commit()
db.refresh(merchant)
return success_response(data=MerchantInfo.model_validate(merchant))
@router.post("/apply", response_model=ResponseModel)
async def apply_merchant(
apply: MerchantApply,
db: Session = Depends(get_db),
user: UserDB = Depends(get_current_user)
):
"""申请成为商家"""
try:
# 创建商家
merchant_apply = MerchantDB(
user_id=user.userid,
name=apply.name,
business_hours=apply.business_hours,
address=apply.address,
longitude=apply.longitude,
latitude=apply.latitude,
phone=apply.phone,
brand_image_url=apply.brand_image_url,
category_id=apply.category_id,
pay_share_rate=apply.pay_share_rate,
status=MerchantStatus.PENDING
)
db.add(merchant_apply)
db.refresh(merchant_apply)
# 创建商家认证信息
auth = db.query(MerchantAuthDB).filter(MerchantAuthDB.merchant_id == merchant_apply.id).first()
if not auth:
merchant_auth = MerchantAuthDB(
merchant_id=merchant_apply.id,
license_image_url=apply.license_image_url,
id_front_url=apply.id_front_url,
id_back_url=apply.id_back_url
)
else:
auth.license_image_url = apply.license_image_url
auth.id_front_url = apply.id_front_url
auth.id_back_url = apply.id_back_url
db.add(merchant_auth)
db.commit()
return success_response()
except Exception as e:
db.rollback()
return error_response(code=500, message=f"申请失败: {str(e)}")
@router.put("/{merchant_id}/approve", response_model=ResponseModel)
async def approve_merchant(
merchant_id: int,
db: Session = Depends(get_db),
admin: UserDB = Depends(get_admin_user)
):
"""审核通过商家申请(管理员)"""
merchant = db.query(MerchantDB).filter(MerchantDB.id == merchant_id).first()
if not merchant:
return error_response(code=404, message="商家不存在")
merchant.status = MerchantStatus.OFFLINE
db.commit()
db.refresh(merchant)
return success_response(data=merchant)
@router.put("/{merchant_id}/offline", response_model=ResponseModel)
async def offline_merchant(
merchant_id: int,
db: Session = Depends(get_db),
admin: UserDB = Depends(get_admin_user)
):
"""下线商家(管理员)"""
merchant = db.query(MerchantDB).filter(MerchantDB.id == merchant_id).first()
if not merchant:
return error_response(code=404, message="商家不存在")
merchant.status = MerchantStatus.OFFLINE
db.commit()
db.refresh(merchant)
return success_response(data=merchant)
@router.get("/{merchant_id}/audit", response_model=ResponseModel)
async def get_merchant_audit(
merchant_id: int,
db: Session = Depends(get_db)
):
"""获取商家审核信息"""
merchant = db.query(MerchantDB).filter(MerchantDB.id == merchant_id).first()
if not merchant:
return error_response(code=404, message="商家不存在")
auth = db.query(MerchantAuthDB).filter(MerchantAuthDB.merchant_id == merchant_id).first()
if not auth:
return error_response(code=404, message="商家认证信息不存在")
result = {
"merchant": MerchantInfo.model_validate(merchant),
"auth": MerchantAuthInfo.model_validate(auth)
}
return success_response(data=result)
@router.post("", response_model=ResponseModel) @router.post("", response_model=ResponseModel)
async def create_merchant( async def create_merchant(
merchant: MerchantCreate, merchant: MerchantCreate,
@ -147,6 +297,7 @@ async def list_merchants(
longitude: Optional[float] = None, longitude: Optional[float] = None,
latitude: Optional[float] = None, latitude: Optional[float] = None,
category_id: Optional[int] = None, category_id: Optional[int] = None,
status: Optional[MerchantStatus] = None,
skip: int = 0, skip: int = 0,
limit: int = 20, limit: int = 20,
db: Session = Depends(get_db) db: Session = Depends(get_db)
@ -165,6 +316,9 @@ async def list_merchants(
MerchantDB.user_id == UserDB.userid MerchantDB.user_id == UserDB.userid
) )
if status is not None:
query = query.filter(MerchantDB.status == status)
# 添加分类过滤 # 添加分类过滤
if category_id is not None: if category_id is not None:
query = query.filter(MerchantDB.category_id == category_id) query = query.filter(MerchantDB.category_id == category_id)

View File

@ -9,16 +9,34 @@ from app.models.user import UserDB
router = APIRouter() router = APIRouter()
@router.post("/upload_merchant_auth_image", response_model=ResponseModel)
async def upload_merchant_auth_image(
image: UploadFile = File(...),
current_user: UserDB = Depends(get_current_user)
):
"""上传商家认证图片"""
if not image.content_type.startswith('image/'):
return error_response(code=400, message="只能上传图片文件")
try:
folder = f"merchant_auth/{current_user.userid}"
url = await qcloud_manager.upload_file(image, folder)
return success_response(data=url)
except Exception as e:
return error_response(code=500, message=f"上传失败: {str(e)}")
@router.post("/image", response_model=ResponseModel) @router.post("/image", response_model=ResponseModel)
async def upload_image( async def upload_image(
file: UploadFile = File(...), file: UploadFile = File(...),
current_user: UserDB = Depends(get_current_user)
): ):
"""上传单张图片""" """上传单张图片"""
if not file.content_type.startswith('image/'): if not file.content_type.startswith('image/'):
return error_response(code=400, message="只能上传图片文件") return error_response(code=400, message="只能上传图片文件")
try: try:
url = await qcloud_manager.upload_file(file) folder = f"uploads/{current_user.userid}"
url = await qcloud_manager.upload_file(file, folder)
return success_response(data=UploadResponse(url=url)) return success_response(data=UploadResponse(url=url))
except Exception as e: except Exception as e:
return error_response(code=500, message=f"上传失败: {str(e)}") return error_response(code=500, message=f"上传失败: {str(e)}")
@ -26,6 +44,7 @@ async def upload_image(
@router.post("/images", response_model=ResponseModel) @router.post("/images", response_model=ResponseModel)
async def upload_images( async def upload_images(
files: List[UploadFile] = File(...), files: List[UploadFile] = File(...),
current_user: UserDB = Depends(get_current_user)
): ):
"""上传多张图片""" """上传多张图片"""
if len(files) > 5: if len(files) > 5:
@ -36,7 +55,8 @@ async def upload_images(
for file in files: for file in files:
if not file.content_type.startswith('image/'): if not file.content_type.startswith('image/'):
return error_response(code=400, message="只能上传图片文件") return error_response(code=400, message="只能上传图片文件")
url = await qcloud_manager.upload_file(file) folder = f"uploads/{current_user.userid}"
url = await qcloud_manager.upload_file(file, folder)
urls.append(url) urls.append(url)
return success_response(data=MultiUploadResponse(urls=urls)) return success_response(data=MultiUploadResponse(urls=urls))
except Exception as e: except Exception as e:

View File

@ -1,4 +1,4 @@
from sqlalchemy import Column, String, Integer, Float, DateTime, JSON, ForeignKey from sqlalchemy import Column, String, Integer, Float, DateTime, JSON, ForeignKey, Enum
from sqlalchemy.dialects.mysql import DECIMAL from sqlalchemy.dialects.mysql import DECIMAL
from sqlalchemy.sql import func, select from sqlalchemy.sql import func, select
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@ -7,6 +7,13 @@ from datetime import datetime
from .database import Base from .database import Base
from app.core.utils import CommonUtils from app.core.utils import CommonUtils
from app.core.imageprocessor import process_image, ImageFormat from app.core.imageprocessor import process_image, ImageFormat
import enum
class MerchantStatus(str, enum.Enum):
"""商家状态枚举"""
PENDING = "PENDING" # 申请中
ONLINE = "ONLINE" # 已上线
OFFLINE = "OFFLINE" # 已下线
# 数据库模型 # 数据库模型
class MerchantDB(Base): class MerchantDB(Base):
@ -23,6 +30,7 @@ class MerchantDB(Base):
brand_image_url = Column(String(200)) # 品牌图片地址 brand_image_url = Column(String(200)) # 品牌图片地址
pay_gift_points_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 支付赠送积分比例默认0% pay_gift_points_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 支付赠送积分比例默认0%
pay_share_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 在线买单分润比例默认0% pay_share_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 在线买单分润比例默认0%
status = Column(Enum(MerchantStatus), default=MerchantStatus.PENDING, nullable=False) # 商家状态
create_time = Column(DateTime(timezone=True), server_default=func.now()) create_time = Column(DateTime(timezone=True), server_default=func.now())
update_time = Column(DateTime(timezone=True), onupdate=func.now()) update_time = Column(DateTime(timezone=True), onupdate=func.now())
category_id = Column(Integer, ForeignKey("merchant_categories.id"), nullable=True) category_id = Column(Integer, ForeignKey("merchant_categories.id"), nullable=True)
@ -43,6 +51,22 @@ class MerchantCreate(BaseModel):
pay_share_rate: Optional[float] = Field(0.00, ge=0, le=100) # 在线买单分润比例 pay_share_rate: Optional[float] = Field(0.00, ge=0, le=100) # 在线买单分润比例
brand_image_url: Optional[str] = Field(None, max_length=200) brand_image_url: Optional[str] = Field(None, max_length=200)
category_id: Optional[int] = None category_id: Optional[int] = None
status: Optional[MerchantStatus] = Field(MerchantStatus.PENDING, description="商家状态")
class MerchantApply(BaseModel):
name: str = Field(..., max_length=100)
business_hours: str = Field(..., max_length=100)
address: str = Field(..., max_length=200)
longitude: float = Field(..., ge=-180, le=180, description="经度")
latitude: float = Field(..., ge=-90, le=90, description="纬度")
phone: str = Field(..., max_length=20, pattern=r'^\d+$')
brand_image_url: str = Field(..., max_length=200)
category_id: int = Field(..., ge=0)
pay_share_rate: float = Field(0.00, ge=0, le=100) # 在线买单分润比例
license_image_url: str = Field(..., max_length=200)
id_front_url: str = Field(..., max_length=200)
id_back_url: str = Field(..., max_length=200)
class MerchantUpdate(BaseModel): class MerchantUpdate(BaseModel):
user_id: Optional[int] = None user_id: Optional[int] = None
@ -56,6 +80,7 @@ class MerchantUpdate(BaseModel):
pay_share_rate: Optional[float] = Field(None, ge=0, le=100) # 在线买单分润比例 pay_share_rate: Optional[float] = Field(None, ge=0, le=100) # 在线买单分润比例
brand_image_url: Optional[str] = Field(None, max_length=200) brand_image_url: Optional[str] = Field(None, max_length=200)
category_id: Optional[int] = None category_id: Optional[int] = None
status: Optional[MerchantStatus] = None
class MerchantInfo(BaseModel): class MerchantInfo(BaseModel):
id: int id: int
@ -74,6 +99,7 @@ class MerchantInfo(BaseModel):
pay_share_rate: float pay_share_rate: float
brand_image_url: Optional[str] = None brand_image_url: Optional[str] = None
optimized_brand_image_url: Optional[str] = None optimized_brand_image_url: Optional[str] = None
status: MerchantStatus # 商家状态
create_time: datetime create_time: datetime
update_time: Optional[datetime] update_time: Optional[datetime]
distance: Optional[int] = None # 距离(米) distance: Optional[int] = None # 距离(米)

View File

@ -0,0 +1,46 @@
from sqlalchemy import Column, String, Integer, DateTime, ForeignKey
from sqlalchemy.sql import func
from pydantic import BaseModel, Field
from typing import Optional
from datetime import datetime
from .database import Base
from sqlalchemy.orm import relationship
class MerchantAuthDB(Base):
"""商家认证信息表"""
__tablename__ = "merchant_auths"
id = Column(Integer, primary_key=True, autoincrement=True)
merchant_id = Column(Integer, ForeignKey("merchants.id"), nullable=False, unique=True) # 商家ID一个商家只能有一条认证信息
license_image_url = Column(String(200), nullable=False) # 营业执照图片URL
id_front_url = Column(String(200), nullable=False) # 身份证正面图片URL
id_back_url = Column(String(200), nullable=False) # 身份证背面图片URL
create_time = Column(DateTime(timezone=True), server_default=func.now())
update_time = Column(DateTime(timezone=True), onupdate=func.now())
# 关联商家
merchant = relationship("MerchantDB", backref="auth_info")
# Pydantic 模型用于API请求和响应
class MerchantAuthCreate(BaseModel):
merchant_id: int = Field(..., description="商家ID")
license_image_url: str = Field(..., description="营业执照图片URL")
id_front_url: str = Field(..., description="身份证正面图片URL")
id_back_url: str = Field(..., description="身份证背面图片URL")
class MerchantAuthUpdate(BaseModel):
license_image_url: Optional[str] = Field(None, description="营业执照图片URL")
id_front_url: Optional[str] = Field(None, description="身份证正面图片URL")
id_back_url: Optional[str] = Field(None, description="身份证背面图片URL")
class MerchantAuthInfo(BaseModel):
id: int
merchant_id: int
license_image_url: str
id_front_url: str
id_back_url: str
create_time: datetime
update_time: Optional[datetime] = None
class Config:
from_attributes = True

View File

@ -1,9 +1,9 @@
from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum, Boolean from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum, Boolean, Date, Text
from sqlalchemy.dialects.mysql import DECIMAL from sqlalchemy.dialects.mysql import DECIMAL
from sqlalchemy.sql import func from sqlalchemy.sql import func
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from typing import Optional, List from typing import Optional, List
from datetime import datetime from datetime import datetime, date
from .database import Base from .database import Base
import enum import enum
from app.core.utils import CommonUtils from app.core.utils import CommonUtils
@ -13,6 +13,16 @@ class ProductStatus(str, enum.Enum):
LISTING = "LISTING" # 上架 LISTING = "LISTING" # 上架
UNLISTING = "UNLISTING" # 下架 UNLISTING = "UNLISTING" # 下架
class DeliveryType(str, enum.Enum):
"""配送类型枚举"""
DELIVERY = "DELIVERY" # 配送到家
PICKUP = "PICKUP" # 自提
class DeliveryTimeType(str, enum.Enum):
"""配送时间类型枚举"""
IMMEDIATE = "IMMEDIATE" # 立即送
SCHEDULED = "SCHEDULED" # 定时送
class MerchantProductDB(Base): class MerchantProductDB(Base):
__tablename__ = "merchant_products" __tablename__ = "merchant_products"
@ -27,6 +37,14 @@ class MerchantProductDB(Base):
purchase_limit = Column(Integer, nullable=False, default=0) # 限购次数0表示不限购 purchase_limit = Column(Integer, nullable=False, default=0) # 限购次数0表示不限购
gift_points_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 购买赠送积分比例默认0% gift_points_rate = Column(DECIMAL(4,2), nullable=False, default=0.00) # 购买赠送积分比例默认0%
promotion_text = Column(String(100)) # 促销文本 promotion_text = Column(String(100)) # 促销文本
product_detail = Column(Text, nullable=True) # 产品详细描述Markdown格式
purchase_note = Column(Text, nullable=True) # 购买须知,用于提供商品购买相关注意事项
qty = Column(Integer, nullable=False, default=0) # 库存
is_sellout = Column(Boolean, nullable=False, default=False) # 是否售罄
delivery_type = Column(Enum(DeliveryType), nullable=False, default=DeliveryType.DELIVERY) # 配送类型
pickup_place = Column(String(200), nullable=True) # 自提点
delivery_time_type = Column(Enum(DeliveryTimeType), nullable=False, default=DeliveryTimeType.IMMEDIATE) # 配送时间类型
delivery_date = Column(Date, nullable=True) # 配送日期,仅对定时送有效
create_time = Column(DateTime(timezone=True), server_default=func.now()) create_time = Column(DateTime(timezone=True), server_default=func.now())
update_time = Column(DateTime(timezone=True), onupdate=func.now()) update_time = Column(DateTime(timezone=True), onupdate=func.now())
status = Column(Enum(ProductStatus), nullable=False, default=ProductStatus.UNLISTING) status = Column(Enum(ProductStatus), nullable=False, default=ProductStatus.UNLISTING)
@ -45,6 +63,14 @@ class MerchantProductCreate(BaseModel):
settlement_amount: float = Field(..., gt=0) settlement_amount: float = Field(..., gt=0)
tags: str = Field("", max_length=200) tags: str = Field("", max_length=200)
purchase_limit: int = Field(0, ge=0) # 限购次数默认0表示不限购 purchase_limit: int = Field(0, ge=0) # 限购次数默认0表示不限购
product_detail: Optional[str] = None # 产品详细描述Markdown格式
purchase_note: Optional[str] = None # 购买须知,用于提供商品购买相关注意事项
qty: int = Field(0, ge=0) # 库存
is_sellout: bool = Field(False) # 是否售罄
delivery_type: DeliveryType = Field(DeliveryType.DELIVERY) # 配送类型
pickup_place: Optional[str] = Field(None, max_length=200) # 自提点
delivery_time_type: DeliveryTimeType = Field(DeliveryTimeType.IMMEDIATE) # 配送时间类型
delivery_date: Optional[date] = Field(None) # 配送日期
status: ProductStatus = ProductStatus.UNLISTING status: ProductStatus = ProductStatus.UNLISTING
promotion_text: Optional[str] = Field(None, max_length=100) # 促销文本 promotion_text: Optional[str] = Field(None, max_length=100) # 促销文本
gift_points_rate: Optional[float] = Field(10.00, ge=0, le=100) # 购买赠送积分比例 gift_points_rate: Optional[float] = Field(10.00, ge=0, le=100) # 购买赠送积分比例
@ -57,6 +83,14 @@ class MerchantProductUpdate(BaseModel):
settlement_amount: Optional[float] = Field(None, gt=0) settlement_amount: Optional[float] = Field(None, gt=0)
tags: Optional[str] = Field(None, max_length=200) tags: Optional[str] = Field(None, max_length=200)
purchase_limit: Optional[int] = Field(None, ge=0) # 限购次数,可选字段 purchase_limit: Optional[int] = Field(None, ge=0) # 限购次数,可选字段
product_detail: Optional[str] = None # 产品详细描述Markdown格式
purchase_note: Optional[str] = None # 购买须知,用于提供商品购买相关注意事项
qty: Optional[int] = Field(None, ge=0) # 库存
is_sellout: Optional[bool] = None # 是否售罄
delivery_type: Optional[DeliveryType] = None # 配送类型
pickup_place: Optional[str] = Field(None, max_length=200) # 自提点
delivery_time_type: Optional[DeliveryTimeType] = None # 配送时间类型
delivery_date: Optional[date] = None # 配送日期
status: Optional[ProductStatus] = None status: Optional[ProductStatus] = None
promotion_text: Optional[str] = Field(None, max_length=100) # 促销文本 promotion_text: Optional[str] = Field(None, max_length=100) # 促销文本
gift_points_rate: Optional[float] = Field(None, ge=0, le=100) # 购买赠送积分比例 gift_points_rate: Optional[float] = Field(None, ge=0, le=100) # 购买赠送积分比例
@ -73,6 +107,14 @@ class MerchantProductInfo(BaseModel):
settlement_amount: float settlement_amount: float
tags: str tags: str
purchase_limit: int # 限购次数 purchase_limit: int # 限购次数
product_detail: Optional[str] = None # 产品详细描述Markdown格式
purchase_note: Optional[str] = None # 购买须知,用于提供商品购买相关注意事项
qty: int # 库存
is_sellout: bool # 是否售罄
delivery_type: DeliveryType # 配送类型
pickup_place: Optional[str] = None # 自提点
delivery_time_type: DeliveryTimeType # 配送时间类型
delivery_date: Optional[date] = None # 配送日期
gift_points_rate: float gift_points_rate: float
promotion_text: Optional[str] = None # 促销文本 promotion_text: Optional[str] = None # 促销文本
create_time: datetime create_time: datetime

37
app/sql/v1.1.sql Normal file
View File

@ -0,0 +1,37 @@
-- 1. 添加库存字段
ALTER TABLE merchant_products
ADD COLUMN qty INT NOT NULL DEFAULT 0 COMMENT '库存数量';
-- 2. 添加是否售罄字段
ALTER TABLE merchant_products
ADD COLUMN is_sellout TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否售罄0-未售罄1-已售罄';
-- 3. 添加配送类型字段使用MySQL的ENUM类型
ALTER TABLE merchant_products
ADD COLUMN delivery_type ENUM('DELIVERY', 'PICKUP') NOT NULL DEFAULT 'DELIVERY' COMMENT '配送类型DELIVERY-配送到家PICKUP-自提';
-- 4. 添加自提点字段
ALTER TABLE merchant_products
ADD COLUMN pickup_place VARCHAR(200) NULL COMMENT '自提点';
-- 5. 添加配送时间类型字段使用MySQL的ENUM类型
ALTER TABLE merchant_products
ADD COLUMN delivery_time_type ENUM('IMMEDIATE', 'SCHEDULED') NOT NULL DEFAULT 'IMMEDIATE' COMMENT '配送时间类型IMMEDIATE-立即送SCHEDULED-定时送';
-- 6. 添加配送日期字段
ALTER TABLE merchant_products
ADD COLUMN delivery_date DATE NULL COMMENT '配送日期,仅对定时送有效';
-- 7. 创建索引以提高查询效率
CREATE INDEX idx_merchant_products_delivery_type ON merchant_products(delivery_type);
CREATE INDEX idx_merchant_products_delivery_time_type ON merchant_products(delivery_time_type);
CREATE INDEX idx_merchant_products_is_sellout ON merchant_products(is_sellout);
-- 为merchant_products表添加product_detail字段
ALTER TABLE merchant_products
ADD COLUMN product_detail TEXT COMMENT '产品详细描述Markdown格式';
-- 为merchant_products表添加purchase_note字段
ALTER TABLE merchant_products
ADD COLUMN purchase_note TEXT COMMENT '购买须知,用于提供商品购买相关注意事项';

Binary file not shown.