"""轮播 / 公告 / 弹窗按俱乐部读取与写入。""" from jituan.constants import CLUB_ID_DEFAULT, DATA_SCOPE_ALL from jituan.services.club_context import ( filter_queryset_by_club, resolve_club_id_from_request, resolve_club_scope, resolve_effective_club_id, ) from rest_framework.response import Response # 定稿 B 方案 page_key LUNBO_PAGE_ORDER_POOL = 'order_pool' LUNBO_PAGE_ACCEPT_ORDER = 'accept_order' LUNBO_PAGE_MERCHANT_HOME = 'merchant_home' LUNBO_PAGE_DASHOU_CENTER = 'dashou_center' LUNBO_PAGE_OPTIONS = [ (LUNBO_PAGE_ORDER_POOL, '抢单池'), (LUNBO_PAGE_ACCEPT_ORDER, '点单页'), (LUNBO_PAGE_MERCHANT_HOME, '商家首页'), (LUNBO_PAGE_DASHOU_CENTER, '打手个人中心背景'), ] # 无商家/打手/管事/组长身份时,仅允许点单相关 page_key PUBLIC_LUNBO_PAGE_KEYS = frozenset({ LUNBO_PAGE_ACCEPT_ORDER, LUNBO_PAGE_ORDER_POOL, }) def normalize_page_key(page_key, image_type=1): key = (page_key or '').strip() if image_type == 2: return LUNBO_PAGE_DASHOU_CENTER if key in {LUNBO_PAGE_ORDER_POOL, LUNBO_PAGE_ACCEPT_ORDER, LUNBO_PAGE_MERCHANT_HOME}: return key return LUNBO_PAGE_ORDER_POOL def _user_role_profile_flags(user): """根据扩展表判断用户是否具备对应身份(比 UserType 更准)。""" if not user or not getattr(user, 'is_authenticated', False): return frozenset() found = set() for attr, name in ( ('ShopProfile', 'shop'), ('DashouProfile', 'dashou'), ('GuanshiProfile', 'guanshi'), ('ZuzhangProfile', 'zuzhang'), ): try: getattr(user, attr) found.add(name) except Exception: pass return frozenset(found) def allowed_lunbo_page_keys_for_user(user): """当前用户可访问的轮播/公告 page_key。""" allowed = set(PUBLIC_LUNBO_PAGE_KEYS) roles = _user_role_profile_flags(user) if 'shop' in roles: allowed.add(LUNBO_PAGE_MERCHANT_HOME) if 'dashou' in roles: allowed.add(LUNBO_PAGE_DASHOU_CENTER) # 管事/组长与点单页共用 order_pool、accept_order,已在 PUBLIC 中 return frozenset(allowed) def resolve_lunbo_page_key_for_request(request, page_key=None, image_type=1): """ 按身份限制 page_key(与小程序 display-config.js 对齐): - order_pool / accept_order:任何人(含未登录)均可访问 - merchant_home / dashou_center:未登录时按前端传入的 page_key 返回(接口 AllowAny、前端不传 JWT) - 已登录时:无对应扩展表身份则拒绝该 page_key(返回 None) """ requested = normalize_page_key(page_key, image_type=image_type) if requested in PUBLIC_LUNBO_PAGE_KEYS: return requested user = getattr(request, 'user', None) if not user or not getattr(user, 'is_authenticated', False): return requested allowed = allowed_lunbo_page_keys_for_user(user) if requested in allowed: return requested return None def forbid_display_write_in_all_scope(request): if resolve_club_scope(request) == DATA_SCOPE_ALL: return Response({'code': 403, 'msg': '请在子公司视图下修改展示配置'}) return None def filter_popup_page_by_request(qs, request): return filter_queryset_by_club(qs, request, club_field='club_id') def forbid_popup_page_out_of_scope(request, page): if resolve_club_scope(request) == DATA_SCOPE_ALL: return None club_id = resolve_club_id_from_request(request) page_club = getattr(page, 'club_id', None) or CLUB_ID_DEFAULT if page_club != club_id: return Response({'code': 403, 'msg': '该弹窗配置不属于当前俱乐部'}) return None def _display_club_id(request): user = getattr(request, 'user', None) if user is not None and getattr(user, 'is_authenticated', False): return resolve_effective_club_id(request, user) return resolve_effective_club_id(request, None) def get_gonggao_content(request, notice_type=1, page_key=None): from config.models import Gonggao club_id = _display_club_id(request) pk = normalize_page_key(page_key, image_type=1) if page_key else LUNBO_PAGE_ORDER_POOL obj = Gonggao.query.filter(club_id=club_id, page_key=pk).first() # 仅旧接口未传 page_key 时,才回退 NoticeType(兼容历史单条公告) if not obj and notice_type and not page_key: obj = Gonggao.query.filter(club_id=club_id, NoticeType=notice_type).first() return obj.Content if obj and obj.Content else '' def get_lunbo_urls(request, page_key=None, image_type=1): from config.models import Lunbo club_id = _display_club_id(request) pk = normalize_page_key(page_key, image_type=image_type) qs = Lunbo.query.filter(club_id=club_id, ImageType=image_type, page_key=pk) return [row.ImageURL for row in qs.order_by('id') if row.ImageURL] def list_response_meta(request): from jituan.services.club_user_access import list_response_meta as _meta return _meta(request) def get_tupianpeizhi_url(request, image_type): """按俱乐部读图片配置(各俱乐部独立,不回退 xq,避免串台)。""" from config.models import Tupianpeizhi club_id = _display_club_id(request) row = Tupianpeizhi.query.filter(club_id=club_id, ImageType=image_type).first() return (row.ImageURL or '').strip() if row else '' TUPIAN_TYPE_LABELS = { 1: '打手规则图', 2: '默认头像', 3: '关注快手', } def list_tupianpeizhi_by_type(club_id, image_type): from config.models import Tupianpeizhi rows = Tupianpeizhi.query.filter(club_id=club_id, ImageType=image_type).order_by('id') return [ {'id': r.id, 'image_url': r.ImageURL or '', 'access_count': r.AccessCount or 0} for r in rows if r.ImageURL ] def upsert_tupianpeizhi_single(club_id, image_type, image_url): """ImageType 1/2 每俱乐部仅一条。""" from config.models import Tupianpeizhi row = Tupianpeizhi.query.filter(club_id=club_id, ImageType=image_type).first() if row: row.ImageURL = image_url row.save(update_fields=['ImageURL', 'UpdateTime']) else: Tupianpeizhi.query.create( club_id=club_id, ImageType=image_type, ImageURL=image_url, AccessCount=0, ) def copy_display_config(template_club_id, new_club_id): """从模板俱乐部复制轮播/公告/弹窗/图片配置到新俱乐部。""" from config.models import Gonggao, Lunbo, PopupConfig, PopupImage, PopupPage, Tupianpeizhi for row in Lunbo.query.filter(club_id=template_club_id): Lunbo.query.create( club_id=new_club_id, page_key=row.page_key or 'order_pool', ImageURL=row.ImageURL, ImageType=row.ImageType, ) for row in Gonggao.query.filter(club_id=template_club_id): Gonggao.query.create( club_id=new_club_id, page_key=getattr(row, 'page_key', None) or 'order_pool', NoticeType=row.NoticeType, Content=row.Content, ) for row in Tupianpeizhi.query.filter(club_id=template_club_id): if Tupianpeizhi.query.filter(club_id=new_club_id, ImageType=row.ImageType).exists(): continue Tupianpeizhi.query.create( club_id=new_club_id, ImageURL=row.ImageURL, ImageType=row.ImageType, AccessCount=0, ) for page in PopupPage.query.filter(club_id=template_club_id).prefetch_related('popups__images'): new_page = PopupPage.query.create( club_id=new_club_id, page_key=page.page_key, name=page.name, description=page.description, is_active=page.is_active, ignore_user_mute=page.ignore_user_mute, ) for popup in page.popups.all(): new_popup = PopupConfig.query.create( page=new_page, popup_id=popup.popup_id, title=popup.title, description=popup.description, strategy_type=popup.strategy_type, max_count=popup.max_count, reset_interval=popup.reset_interval, duration=popup.duration, force_even_muted=popup.force_even_muted, sort_order=popup.sort_order, is_active=popup.is_active, start_time=popup.start_time, end_time=popup.end_time, ) for img in popup.images.all(): PopupImage.query.create( popup_config=new_popup, image_url=img.image_url, text=img.text, sort_order=img.sort_order, ) from jituan.services.miniapp_assets import copy_miniapp_assets copy_miniapp_assets(template_club_id, new_club_id)