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:
2026-06-17 21:32:10 +08:00
parent 7368a1ca8a
commit d55f47fc59
7 changed files with 122 additions and 9 deletions
+17
View File
@@ -67,6 +67,23 @@ def save_report_image(user_id: int, data: bytes) -> str:
return _save_image("price_report", user_id, data)
def save_cps_image(admin_id: int, data: bytes) -> str:
"""保存 CPS 活动落地页图,返回相对 URL(`/media/cps/<file>`)。admin_id 入文件名便于追溯。"""
return _save_image("cps", admin_id, data)
def to_abs_media_url(rel_url: str | None) -> str | None:
"""相对 `/media/...` → 基于 CPS_REDIRECT_BASE 的绝对 URL(CPS 落地页域名,跨域可访问)。
已是绝对 URL / 空 / base 未配(dev) 时原样返回。CPS 活动图入库前转绝对,使落地页
(coupon 域)与 admin-web(另一域,不 serve /media)都能直接 <img src> 加载。
"""
if not rel_url or rel_url.startswith(("http://", "https://")):
return rel_url
base = settings.CPS_REDIRECT_BASE.rstrip("/")
return f"{base}{rel_url}" if base else rel_url
def delete_avatar(url: str | None) -> None:
"""删除本服务托管的旧头像文件;外部 URL(如微信头像)或空值不处理。"""
prefix = f"{settings.MEDIA_URL_PREFIX}/avatars/"