from datetime import datetime, timezone from fastapi.logger import logger from sqlalchemy import and_ from shared.enums import AD_TYPE_LIST from shared.constants import PAGE_SIZE from modules.cms.ad.schemas import AdForm, AdStatusForm from modules.cms.ad.models import Ad from modules.cms.ad.repository import ad_repo from modules.cms.ad_sort.models import AdSort from config import FASTAPI_IMAGE_URL from core.database import get_db_session from core import R from utils.rich_text import get_file_url, save_file, save_content from utils.request import like_contains from core.security import get_user_id # 查询广告分页数据 def get_ad_page(request): db = get_db_session() # 页码 page = int(request.query_params.get("pageNo", 1)) # 每页数 limit = int(request.query_params.get("pageSize", PAGE_SIZE)) # 实例化查询对象 query = ad_repo.filter(Ad.is_delete == 0) # 广告标题 title = request.query_params.get('title') if title: query = query.filter(Ad.title.like(like_contains(title), escape='\\')) # 广告类型:1-图片 2-文字 3-视频 4-推荐 type = request.query_params.get('type') if type: query = query.filter(Ad.type == type) # 广告状态 status = request.query_params.get('status') if status: query = query.filter(Ad.status == status) # 排序 query = query.order_by(Ad.sort.desc()) # 记录总数 count = query.count() # 分页查询 ad_list = query.limit(limit).offset((page - 1) * limit).all() # 若当前页超出末页(数据被并发删除),自动回退到第一页 if page > 1 and not ad_list: page = 1 count = query.count() ad_list = query.limit(limit).offset(0).all() # 实例化结果 result = [] # 遍历数据源 if len(ad_list) > 0: for item in ad_list: # 对象转字典 data = item.to_dict() # 广告类型 data['type_name'] = AD_TYPE_LIST.get(item.type) # 广告封面 data['cover'] = get_file_url(item.cover) if item.cover else None # 查询广告位信息 ad_sort = db.query(AdSort).filter(and_(AdSort.id == item.sort_id, AdSort.is_delete == 0)).first() # 广告位描述 data['sort_desc'] = ad_sort.name + "=>" + str(ad_sort.loc_id) if ad_sort else None # 加入列表 result.append(data) # 返回结果 return R.ok(data=result, count=count) # 根据广告ID查询详情 def get_ad_detail(ad_id): # 根据广告ID查询信息 ad = ad_repo.get_by_id(ad_id) # 查询结果为空判断 if not ad: return None # 对象转字典 data = ad.to_dict() # 广告类型描述 data['type_name'] = AD_TYPE_LIST.get(ad.type) # 广告封面 data['cover'] = get_file_url(ad.cover) if ad.cover else "" # # 富文本内容 # content = ad.content.replace("[IMG_URL]", FASTAPI_IMAGE_URL) # data['content'] = content # 返回结果 return data # 添加广告 def add_ad(request, data: AdForm): # 广告封面(cover 列 NOT NULL,非图片广告用空字符串占位) cover = data.cover or "" if data.type == 1 and cover: cover = save_file(cover, "ad") # # 广告标题 # title = data.title # # 广告内容 # content = data.content # # 处理富文本内容 # content = save_content(content, title, "ad") # 表单数据赋值给对象并插入(cover 用处理后的文件路径,排除表单原值避免重复传参) ad_repo.create(**data.model_dump(exclude={'id', 'cover'}), cover=cover, create_user=get_user_id(request)) # 返回结果 return R.ok(msg="添加成功") # 更新广告 def update_ad(request, data: AdForm): # 记录ID判空 if not data.id or data.id <= 0: return R.failed("记录ID不能为空") # 根据ID查询记录 ad = ad_repo.get_by_id(data.id) # 查询结果判空 if not ad: return R.failed("记录不存在") # 广告封面(cover 列 NOT NULL,非图片广告用空字符串占位) cover = data.cover or "" if data.type == 1 and cover: cover = save_file(cover, "ad") # # 广告标题 # title = data.title # # 广告内容 # content = data.content # # 处理富文本内容 # content = save_content(content, title, "ad") # 构造更新数据(排除 id) updData = data.model_dump(exclude={'id'}) updData['cover'] = cover updData['update_user'] = get_user_id(request) updData['update_time'] = datetime.now(tz=timezone.utc) # 更新记录 result = ad_repo.update(data.id, updData) # 提交数据 # 返回结果 if not result: return R.failed("更新失败") # 返回结果 return R.ok(msg="更新成功") # 删除广告 def delete_ad(ad_id): return ad_repo.batch_delete_r(ad_id) # 设置状态 def update_ad_status(request, data: AdStatusForm): # 根据ID查询记录 ad = ad_repo.get_by_id(data.id) # 查询结果判空 if not ad: return R.failed("记录不存在") # 更新记录 result = ad_repo.update(data.id, { "status": data.status, "update_user": get_user_id(request), "update_time": datetime.now(tz=timezone.utc) }) # 提交数据 if not result: return R.failed("设置失败") # 返回结果 return R.ok(msg="设置成功")