- 完整撰写玉宗珠宝设计大师项目README,介绍项目概况及核心功能 - 说明用户认证系统实现及优势,包含JWT鉴权和密码加密细节 - 详细描述品类管理系统,支持多流程类型和多种玉石品类 - 说明设计图生成方案及技术,包含Pillow生成示例及字体支持 - 介绍设计管理功能,支持分页浏览、预览、下载和删除设计 - 个人信息管理模块说明,涵盖昵称、手机号、密码的安全修改 - 绘制业务流程图和关键数据流图,清晰展现系统架构与数据流 - 提供详细API调用链路及参数说明,涵盖用户、品类、设计接口 - 列明技术栈及版本,包含前后端框架、ORM、认证、加密等工具 - 展示目录结构,标明后端与前端项目布局 - 规划本地开发环境与启动步骤,包括数据库初始化及运行命令 - 说明服务器部署流程和Nginx配置方案 - 详细数据库表结构说明及环境变量配置指导 - 汇总常用开发及测试命令,方便开发调试与部署管理
151 lines
4.1 KiB
Python
151 lines
4.1 KiB
Python
"""
|
||
设计服务
|
||
处理设计相关的业务逻辑
|
||
"""
|
||
import os
|
||
from typing import List, Optional, Tuple
|
||
from sqlalchemy.orm import Session
|
||
from sqlalchemy import desc
|
||
|
||
from ..models import Design, Category, SubType, Color
|
||
from ..schemas import DesignCreate
|
||
from ..config import settings
|
||
from .mock_generator import generate_mock_design
|
||
|
||
|
||
def create_design(db: Session, user_id: int, design_data: DesignCreate) -> Design:
|
||
"""
|
||
创建设计记录
|
||
|
||
1. 创建设计记录(status=generating)
|
||
2. 调用 mock_generator 生成图片
|
||
3. 更新设计记录(status=completed, image_url)
|
||
4. 返回设计对象
|
||
"""
|
||
# 获取关联信息
|
||
category = db.query(Category).filter(Category.id == design_data.category_id).first()
|
||
if not category:
|
||
raise ValueError(f"品类不存在: {design_data.category_id}")
|
||
|
||
sub_type = None
|
||
if design_data.sub_type_id:
|
||
sub_type = db.query(SubType).filter(SubType.id == design_data.sub_type_id).first()
|
||
|
||
color = None
|
||
if design_data.color_id:
|
||
color = db.query(Color).filter(Color.id == design_data.color_id).first()
|
||
|
||
# 创建设计记录
|
||
design = Design(
|
||
user_id=user_id,
|
||
category_id=design_data.category_id,
|
||
sub_type_id=design_data.sub_type_id,
|
||
color_id=design_data.color_id,
|
||
prompt=design_data.prompt,
|
||
carving_technique=design_data.carving_technique,
|
||
design_style=design_data.design_style,
|
||
motif=design_data.motif,
|
||
size_spec=design_data.size_spec,
|
||
surface_finish=design_data.surface_finish,
|
||
usage_scene=design_data.usage_scene,
|
||
status="generating"
|
||
)
|
||
db.add(design)
|
||
db.flush() # 获取 ID
|
||
|
||
# 生成图片
|
||
save_path = os.path.join(settings.UPLOAD_DIR, "designs", f"{design.id}.png")
|
||
image_url = generate_mock_design(
|
||
category_name=category.name,
|
||
sub_type_name=sub_type.name if sub_type else None,
|
||
color_name=color.name if color else None,
|
||
prompt=design_data.prompt,
|
||
save_path=save_path,
|
||
carving_technique=design_data.carving_technique,
|
||
design_style=design_data.design_style,
|
||
motif=design_data.motif,
|
||
size_spec=design_data.size_spec,
|
||
surface_finish=design_data.surface_finish,
|
||
usage_scene=design_data.usage_scene,
|
||
)
|
||
|
||
# 更新设计记录
|
||
design.image_url = image_url
|
||
design.status = "completed"
|
||
db.commit()
|
||
db.refresh(design)
|
||
|
||
return design
|
||
|
||
|
||
def get_user_designs(
|
||
db: Session,
|
||
user_id: int,
|
||
page: int = 1,
|
||
page_size: int = 20
|
||
) -> Tuple[List[Design], int]:
|
||
"""
|
||
分页查询用户设计历史
|
||
|
||
Returns:
|
||
(设计列表, 总数)
|
||
"""
|
||
query = db.query(Design).filter(Design.user_id == user_id)
|
||
|
||
# 获取总数
|
||
total = query.count()
|
||
|
||
# 分页查询,按创建时间倒序
|
||
offset = (page - 1) * page_size
|
||
designs = query.order_by(desc(Design.created_at)).offset(offset).limit(page_size).all()
|
||
|
||
return designs, total
|
||
|
||
|
||
def get_design_by_id(db: Session, design_id: int, user_id: int) -> Optional[Design]:
|
||
"""
|
||
获取单个设计
|
||
只返回属于该用户的设计
|
||
"""
|
||
return db.query(Design).filter(
|
||
Design.id == design_id,
|
||
Design.user_id == user_id
|
||
).first()
|
||
|
||
|
||
def delete_design(db: Session, design_id: int, user_id: int) -> bool:
|
||
"""
|
||
删除设计
|
||
|
||
1. 查找设计(必须属于该用户)
|
||
2. 删除图片文件
|
||
3. 删除数据库记录
|
||
|
||
Returns:
|
||
是否删除成功
|
||
"""
|
||
design = db.query(Design).filter(
|
||
Design.id == design_id,
|
||
Design.user_id == user_id
|
||
).first()
|
||
|
||
if not design:
|
||
return False
|
||
|
||
# 删除图片文件
|
||
if design.image_url:
|
||
# image_url 格式: /uploads/designs/1001.png
|
||
# 转换为实际文件路径
|
||
file_path = design.image_url.lstrip("/")
|
||
if os.path.exists(file_path):
|
||
try:
|
||
os.remove(file_path)
|
||
except Exception:
|
||
pass # 忽略删除失败
|
||
|
||
# 删除数据库记录
|
||
db.delete(design)
|
||
db.commit()
|
||
|
||
return True
|