feat(cps): 淘宝活动落地页图做活——每活动关联图,运营上传/选已有
- model: cps_activity.image_url + 迁移 cps_activity_image 回填存量淘宝活动为现有图 - admin: 新建淘宝活动必传图(上传 /upload-image 或选已有 /activity-images),存绝对 URL - 落地页 cps_redirect: 按 link→activity 取图展示,缺图兜底默认图,img src 经 html.escape - media: save_cps_image + to_abs_media_url(基于 CPS_REDIRECT_BASE,跨域 admin-web 可显示) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ import time
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, Query, Request, UploadFile
|
||||
|
||||
from app.admin.audit import write_audit
|
||||
from app.admin.deps import AdminDb, get_client_ip, get_current_admin, require_role
|
||||
@@ -30,6 +30,7 @@ from app.admin.schemas.cps import (
|
||||
CpsReferralLinksRequest,
|
||||
CpsStatsOut,
|
||||
)
|
||||
from app.core import media
|
||||
from app.core.config import settings
|
||||
from app.integrations import meituan
|
||||
from app.integrations.meituan import MeituanCpsError
|
||||
@@ -154,10 +155,12 @@ def create_activity(
|
||||
if not body.payload:
|
||||
label = "淘口令" if body.platform == "taobao" else "推广链接"
|
||||
raise HTTPException(status_code=400, detail=f"{body.platform} 活动需填{label}")
|
||||
if body.platform == "taobao" and not body.image_url:
|
||||
raise HTTPException(status_code=400, detail="淘宝活动需提供落地页图(上传或选已有)")
|
||||
activity = cps_repo.create_activity(
|
||||
db, name=body.name, platform=body.platform, act_id=body.act_id,
|
||||
product_view_sign=body.product_view_sign, payload=body.payload,
|
||||
remark=body.remark, commit=False,
|
||||
image_url=media.to_abs_media_url(body.image_url), remark=body.remark, commit=False,
|
||||
)
|
||||
write_audit(
|
||||
db, admin, action="cps.activity.create", target_type="cps_activity", target_id=activity.id,
|
||||
@@ -169,6 +172,24 @@ def create_activity(
|
||||
return CpsActivityOut.model_validate(activity)
|
||||
|
||||
|
||||
@router.post("/upload-image", summary="上传活动落地页图(返回绝对 URL)")
|
||||
async def upload_activity_image(
|
||||
admin: Annotated[AdminUser, Depends(require_role("operator"))],
|
||||
file: UploadFile = File(..., description="落地页图(jpeg/png/webp,≤5MB)"),
|
||||
) -> dict:
|
||||
data = await file.read()
|
||||
try:
|
||||
url = media.save_cps_image(admin.id, data)
|
||||
except media.MediaError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e)) from e
|
||||
return {"url": media.to_abs_media_url(url)}
|
||||
|
||||
|
||||
@router.get("/activity-images", summary="已有活动落地页图(供新建复用选择)")
|
||||
def activity_images(db: AdminDb) -> dict:
|
||||
return {"images": cps_repo.list_activity_images(db)}
|
||||
|
||||
|
||||
# ───────────── 生成链接(批量,按平台分支) ─────────────
|
||||
def _gen_one_link(db, group: CpsGroup, activity: CpsActivity):
|
||||
"""给一个活动生成一条落地页 link。美团:转链拿短链(需群 sid);淘宝/京东:用 payload。"""
|
||||
|
||||
Reference in New Issue
Block a user