fix: 会员/图标换图生成新路径并删除旧OSS,避免CDN缓存导致不更新
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -276,9 +276,13 @@ MEMBER_CARD_FOLDER = 'beijing/huiyuan'
|
||||
|
||||
|
||||
def upload_member_card_image(request, huiyuan_id, field, file_obj):
|
||||
"""上传会员充值页卡片图,写入 club_huiyuan_price.card_image / card_bg。"""
|
||||
"""上传会员充值页卡片图,写入 club_huiyuan_price.card_image / card_bg。
|
||||
|
||||
每次上传生成新相对路径并删除旧图,避免「同名覆盖但 CDN/浏览器仍显示旧图」。
|
||||
"""
|
||||
import os
|
||||
from utils.oss_utils import validate_image, upload_to_oss
|
||||
import uuid
|
||||
from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss
|
||||
|
||||
if club_write_blocked(request):
|
||||
return None, CLUB_WRITE_SCOPE_MSG
|
||||
@@ -289,18 +293,36 @@ def upload_member_card_image(request, huiyuan_id, field, file_obj):
|
||||
return None, msg
|
||||
|
||||
club_id = club_id_for_write(request)
|
||||
ext = os.path.splitext(getattr(file_obj, 'name', '') or '')[1].lower()
|
||||
if ext not in ('.png', '.jpg', '.jpeg', '.webp', '.gif'):
|
||||
ext = '.png'
|
||||
rel_path = f'{MEMBER_CARD_FOLDER}/{club_id}/{huiyuan_id}_{field}{ext}'
|
||||
if not upload_to_oss(file_obj, rel_path):
|
||||
return None, '上传 OSS 失败'
|
||||
|
||||
row = ClubHuiyuanPrice.query.filter(club_id=club_id, huiyuan_id=huiyuan_id).first()
|
||||
if not row:
|
||||
return None, '请先在当前俱乐部上架该会员'
|
||||
|
||||
ext = os.path.splitext(getattr(file_obj, 'name', '') or '')[1].lower()
|
||||
if ext not in ('.png', '.jpg', '.jpeg', '.webp', '.gif'):
|
||||
ext = '.png'
|
||||
# 带时间戳+uuid,保证 URL 变化,前端/CDN 不会命中旧缓存
|
||||
stamp = uuid.uuid4().hex[:12]
|
||||
rel_path = f'{MEMBER_CARD_FOLDER}/{club_id}/{huiyuan_id}_{field}_{stamp}{ext}'
|
||||
|
||||
if hasattr(file_obj, 'seek'):
|
||||
try:
|
||||
file_obj.seek(0)
|
||||
except Exception:
|
||||
pass
|
||||
if not upload_to_oss(file_obj, rel_path):
|
||||
return None, '上传 OSS 失败'
|
||||
|
||||
old_path = (getattr(row, field, None) or '').strip()
|
||||
setattr(row, field, rel_path)
|
||||
row.save(update_fields=[field, 'UpdateTime'])
|
||||
|
||||
if old_path and old_path != rel_path:
|
||||
try:
|
||||
delete_from_oss(old_path)
|
||||
except Exception as e:
|
||||
logger.warning('删除旧会员卡片图失败 club=%s hy=%s field=%s path=%s err=%s',
|
||||
club_id, huiyuan_id, field, old_path, e)
|
||||
|
||||
return {field: rel_path, 'huiyuan_id': huiyuan_id}, None
|
||||
|
||||
|
||||
|
||||
@@ -129,12 +129,20 @@ def list_tupianpeizhi_by_type(club_id, image_type):
|
||||
|
||||
|
||||
def upsert_tupianpeizhi_single(club_id, image_type, image_url):
|
||||
"""ImageType 1/2 每俱乐部仅一条。"""
|
||||
"""ImageType 1/2 每俱乐部仅一条;换图时删除旧 OSS 对象。"""
|
||||
from config.models import Tupianpeizhi
|
||||
from utils.oss_utils import delete_from_oss
|
||||
|
||||
row = Tupianpeizhi.query.filter(club_id=club_id, ImageType=image_type).first()
|
||||
if row:
|
||||
old = (row.ImageURL or '').strip()
|
||||
row.ImageURL = image_url
|
||||
row.save(update_fields=['ImageURL', 'UpdateTime'])
|
||||
if old and old != image_url:
|
||||
try:
|
||||
delete_from_oss(old)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
Tupianpeizhi.query.create(
|
||||
club_id=club_id, ImageType=image_type, ImageURL=image_url, AccessCount=0,
|
||||
|
||||
@@ -138,15 +138,22 @@ class ClubMiniappIconManageView(APIView):
|
||||
ext = os.path.splitext(file_obj.name)[1].lower() or '.png'
|
||||
if ext not in ('.png', '.jpg', '.jpeg', '.webp'):
|
||||
ext = '.png'
|
||||
import uuid
|
||||
stamp = uuid.uuid4().hex[:12]
|
||||
# 路径必须含 club_id + 唯一后缀:否则同名覆盖后 CDN 仍显示旧图,且会串俱乐部
|
||||
if icon_key in POSTER_ICON_KEYS:
|
||||
oss_path = f'{POSTER_FOLDER}/{club_id}_{icon_key}{ext}'
|
||||
oss_path = f'{POSTER_FOLDER}/{club_id}_{icon_key}_{stamp}{ext}'
|
||||
else:
|
||||
oss_path = f'{ICON_FOLDER}/{icon_key}{ext}'
|
||||
oss_path = f'{ICON_FOLDER}/{club_id}/{icon_key}_{stamp}{ext}'
|
||||
|
||||
row = ClubMiniappIcon.query.filter(club_id=club_id, icon_key=icon_key).first()
|
||||
if row and row.image_path and row.image_path != oss_path:
|
||||
delete_from_oss(row.image_path)
|
||||
old_path = (row.image_path or '').strip() if row else ''
|
||||
|
||||
if hasattr(file_obj, 'seek'):
|
||||
try:
|
||||
file_obj.seek(0)
|
||||
except Exception:
|
||||
pass
|
||||
if not upload_to_oss(file_obj, oss_path):
|
||||
return Response({'code': 500, 'msg': '图片上传失败'})
|
||||
|
||||
@@ -165,6 +172,11 @@ class ClubMiniappIconManageView(APIView):
|
||||
is_active=True,
|
||||
is_uploaded=True,
|
||||
)
|
||||
if old_path and old_path != oss_path:
|
||||
try:
|
||||
delete_from_oss(old_path)
|
||||
except Exception:
|
||||
pass
|
||||
return Response({'code': 0, 'msg': '上传成功', 'data': {'image_path': oss_path}})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user