feat: 打手中心全量可配置图标下发与会员卡片图上传接口
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -44,6 +44,7 @@ from .views.products import (
|
|||||||
from .views.members import (
|
from .views.members import (
|
||||||
GetMemberListView, UpdateMemberView, AddMemberView,
|
GetMemberListView, UpdateMemberView, AddMemberView,
|
||||||
ClubMemberCatalogView, ClubMemberEnableView, ClubMemberDisableView,
|
ClubMemberCatalogView, ClubMemberEnableView, ClubMemberDisableView,
|
||||||
|
MemberCardImageUploadView,
|
||||||
)
|
)
|
||||||
from .views.guanli import (
|
from .views.guanli import (
|
||||||
GetGuanliListView, GetGuanliDetailView, PromoteGuanshiToZuzhangView,
|
GetGuanliListView, GetGuanliDetailView, PromoteGuanshiToZuzhangView,
|
||||||
@@ -102,6 +103,7 @@ __all__ = [
|
|||||||
# members
|
# members
|
||||||
'GetMemberListView', 'UpdateMemberView', 'AddMemberView',
|
'GetMemberListView', 'UpdateMemberView', 'AddMemberView',
|
||||||
'ClubMemberCatalogView', 'ClubMemberEnableView', 'ClubMemberDisableView',
|
'ClubMemberCatalogView', 'ClubMemberEnableView', 'ClubMemberDisableView',
|
||||||
|
'MemberCardImageUploadView',
|
||||||
# guanli
|
# guanli
|
||||||
'GetGuanliListView', 'GetGuanliDetailView', 'PromoteGuanshiToZuzhangView',
|
'GetGuanliListView', 'GetGuanliDetailView', 'PromoteGuanshiToZuzhangView',
|
||||||
'UpdateGuanliView',
|
'UpdateGuanliView',
|
||||||
|
|||||||
@@ -349,5 +349,27 @@ class ClubMemberDisableView(APIView):
|
|||||||
return Response({'code': 0, 'msg': '已下架', 'data': data})
|
return Response({'code': 0, 'msg': '已下架', 'data': data})
|
||||||
|
|
||||||
|
|
||||||
|
class MemberCardImageUploadView(APIView):
|
||||||
|
"""POST /jituan/houtai/hy-card-upload 上传会员充值卡片图"""
|
||||||
|
permission_classes = []
|
||||||
|
parser_classes = [MultiPartParser, FormParser, JSONParser]
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
username = (request.data.get('username') or request.data.get('phone') or '').strip()
|
||||||
|
huiyuan_id = (request.data.get('huiyuan_id') or '').strip()
|
||||||
|
field = (request.data.get('field') or 'card_image').strip()
|
||||||
|
file_obj = request.FILES.get('file')
|
||||||
|
if not username or not huiyuan_id or not file_obj:
|
||||||
|
return Response({'code': 400, 'msg': '参数不完整'})
|
||||||
|
kefu, permissions = verify_kefu_permission(request, username)
|
||||||
|
if kefu is None:
|
||||||
|
return permissions
|
||||||
|
if '3300a' not in permissions:
|
||||||
|
return Response({'code': 403, 'msg': '无权限'})
|
||||||
|
from jituan.services.club_member_admin import upload_member_card_image
|
||||||
|
data, err = upload_member_card_image(request, huiyuan_id, field, file_obj)
|
||||||
|
if err:
|
||||||
|
return Response({'code': 400, 'msg': err})
|
||||||
|
return Response({'code': 0, 'msg': '上传成功', 'data': data})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -228,6 +228,38 @@ def update_member_for_club(request, huiyuan_id, jieshao, jiage, guanshifc, zuzha
|
|||||||
return {'huiyuan_id': huiyuan_id}, None
|
return {'huiyuan_id': huiyuan_id}, None
|
||||||
|
|
||||||
|
|
||||||
|
MEMBER_CARD_FOLDER = 'beijing/huiyuan'
|
||||||
|
|
||||||
|
|
||||||
|
def upload_member_card_image(request, huiyuan_id, field, file_obj):
|
||||||
|
"""上传会员充值页卡片图,写入 club_huiyuan_price.card_image / card_bg。"""
|
||||||
|
import os
|
||||||
|
from utils.oss_utils import validate_image, upload_to_oss
|
||||||
|
|
||||||
|
if club_write_blocked(request):
|
||||||
|
return None, CLUB_WRITE_SCOPE_MSG
|
||||||
|
if field not in ('card_image', 'card_bg'):
|
||||||
|
return None, '无效的图字段'
|
||||||
|
ok, msg = validate_image(file_obj)
|
||||||
|
if not ok:
|
||||||
|
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, '请先在当前俱乐部上架该会员'
|
||||||
|
setattr(row, field, rel_path)
|
||||||
|
row.save(update_fields=[field, 'UpdateTime'])
|
||||||
|
return {field: rel_path, 'huiyuan_id': huiyuan_id}, None
|
||||||
|
|
||||||
|
|
||||||
def enable_member_for_club(request, huiyuan_id, jiage, guanshifc, zuzhangfc, extra=None):
|
def enable_member_for_club(request, huiyuan_id, jiage, guanshifc, zuzhangfc, extra=None):
|
||||||
"""俱乐部上架集团会员类型。"""
|
"""俱乐部上架集团会员类型。"""
|
||||||
if club_write_blocked(request):
|
if club_write_blocked(request):
|
||||||
|
|||||||
@@ -29,6 +29,49 @@ MINIAPP_ICON_META = [
|
|||||||
('fighter_recharge_vip_bg', '打手会员充值页-顶部背景图'),
|
('fighter_recharge_vip_bg', '打手会员充值页-顶部背景图'),
|
||||||
('fighter_deposit_bg', '打手保证金页-顶部背景图'),
|
('fighter_deposit_bg', '打手保证金页-顶部背景图'),
|
||||||
('fighter_deposit_hero', '打手保证金页-卡片右侧装饰图'),
|
('fighter_deposit_hero', '打手保证金页-卡片右侧装饰图'),
|
||||||
|
('fighter_deposit_benefit_1', '保证金页-权益图标1'),
|
||||||
|
('fighter_deposit_benefit_2', '保证金页-权益图标2'),
|
||||||
|
('fighter_deposit_benefit_3', '保证金页-权益图标3'),
|
||||||
|
('fighter_deposit_benefit_4', '保证金页-权益图标4'),
|
||||||
|
('fighter_recharge_benefit_1', '会员充值页-权益图标1'),
|
||||||
|
('fighter_recharge_benefit_2', '会员充值页-权益图标2'),
|
||||||
|
('fighter_recharge_benefit_3', '会员充值页-权益图标3'),
|
||||||
|
('fighter_recharge_advantage_1', '会员充值页-平台优势1'),
|
||||||
|
('fighter_recharge_advantage_2', '会员充值页-平台优势2'),
|
||||||
|
('fighter_recharge_advantage_3', '会员充值页-平台优势3'),
|
||||||
|
('fighter_recharge_advantage_4', '会员充值页-平台优势4'),
|
||||||
|
('fighter_order_pending', '打手中心-订单-待完成'),
|
||||||
|
('fighter_order_settling', '打手中心-订单-待结算'),
|
||||||
|
('fighter_order_done', '打手中心-订单-已完成'),
|
||||||
|
('fighter_order_closed', '打手中心-订单-已关闭'),
|
||||||
|
('fighter_trade_commission', '打手中心-佣金记录'),
|
||||||
|
('fighter_trade_withdraw', '打手中心-提现记录'),
|
||||||
|
('fighter_trade_settle', '打手中心-结算记录'),
|
||||||
|
('fighter_trade_deduct', '打手中心-扣款记录'),
|
||||||
|
('fighter_trade_recharge', '打手中心-充值记录'),
|
||||||
|
('fighter_invite_subordinate', '打手中心-我的下级'),
|
||||||
|
('fighter_invite_poster', '打手中心-推广海报'),
|
||||||
|
('fighter_invite_code', '打手中心-邀请码'),
|
||||||
|
('fighter_kuaishou_cash', '打手中心-快手提现'),
|
||||||
|
('fighter_mine_copy', '打手中心-复制ID'),
|
||||||
|
('fighter_mine_edit', '打手中心-编辑资料'),
|
||||||
|
('fighter_mine_qiepian', '打手中心-切片活动横幅'),
|
||||||
|
('fighter_mine_penalty_tip', '打手中心-罚单提示图标'),
|
||||||
|
('fighter_mine_kefu', '打手中心-在线客服'),
|
||||||
|
('fighter_mine_shangjia', '打手中心-商家认证'),
|
||||||
|
('fighter_mine_punish', '打手中心-我的处罚'),
|
||||||
|
('fighter_mine_medal', '打手中心-考核金牌'),
|
||||||
|
('fighter_mine_book', '打手中心-接单考试/规则'),
|
||||||
|
('fighter_mine_rank', '打手中心-总排行榜'),
|
||||||
|
('fighter_mine_invite', '打手中心-联系邀请人'),
|
||||||
|
('fighter_mine_contact', '打手中心-联系组长'),
|
||||||
|
('fighter_mine_record', '打手中心-会员/分红记录'),
|
||||||
|
('fighter_mine_kaohe_dafen', '打手中心-考核打分'),
|
||||||
|
('fighter_mine_kaohe_jilu', '打手中心-考核记录'),
|
||||||
|
('fighter_mine_kaohe_zhongxin', '打手中心-考核中心'),
|
||||||
|
('fighter_mine_dashou_auth', '打手中心-接单员认证'),
|
||||||
|
('fighter_mine_clear', '打手中心-清除缓存'),
|
||||||
|
('fighter_mine_switch', '打手中心-返回点单端'),
|
||||||
('mine_pindao', '频道入口'),
|
('mine_pindao', '频道入口'),
|
||||||
('icon_refresh', '通用刷新'),
|
('icon_refresh', '通用刷新'),
|
||||||
('guanshi_poster_bg', '管事推广海报背景'),
|
('guanshi_poster_bg', '管事推广海报背景'),
|
||||||
@@ -58,7 +101,39 @@ MINIAPP_ICON_DEFAULTS['fighter_recharge_deposit'] = f'{ICON_FOLDER}/fighter_rech
|
|||||||
MINIAPP_ICON_DEFAULTS['fighter_recharge_vip_bg'] = f'{ICON_FOLDER}/fighter_recharge_vip_bg.png'
|
MINIAPP_ICON_DEFAULTS['fighter_recharge_vip_bg'] = f'{ICON_FOLDER}/fighter_recharge_vip_bg.png'
|
||||||
MINIAPP_ICON_DEFAULTS['fighter_deposit_bg'] = f'{ICON_FOLDER}/fighter_deposit_bg.png'
|
MINIAPP_ICON_DEFAULTS['fighter_deposit_bg'] = f'{ICON_FOLDER}/fighter_deposit_bg.png'
|
||||||
MINIAPP_ICON_DEFAULTS['fighter_deposit_hero'] = f'{ICON_FOLDER}/fighter_deposit_hero.png'
|
MINIAPP_ICON_DEFAULTS['fighter_deposit_hero'] = f'{ICON_FOLDER}/fighter_deposit_hero.png'
|
||||||
MINIAPP_ICON_DEFAULTS['mine_pindao'] = 'beijing/tubiao/grzx_guanzhualong.jpg'
|
MINIAPP_ICON_DEFAULTS['fighter_order_pending'] = f'{ICON_FOLDER}/fighter_order_pending.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_order_settling'] = f'{ICON_FOLDER}/fighter_order_settling.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_order_done'] = f'{ICON_FOLDER}/fighter_order_done.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_order_closed'] = f'{ICON_FOLDER}/fighter_order_closed.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_trade_commission'] = f'{ICON_FOLDER}/fighter_trade_commission.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_trade_withdraw'] = f'{ICON_FOLDER}/fighter_trade_withdraw.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_trade_settle'] = f'{ICON_FOLDER}/fighter_trade_settle.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_trade_deduct'] = f'{ICON_FOLDER}/fighter_trade_deduct.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_trade_recharge'] = f'{ICON_FOLDER}/fighter_trade_recharge.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_invite_subordinate'] = f'{ICON_FOLDER}/fighter_invite_subordinate.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_invite_poster'] = f'{ICON_FOLDER}/fighter_invite_poster.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_invite_code'] = f'{ICON_FOLDER}/fighter_invite_code.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_kuaishou_cash'] = f'{ICON_FOLDER}/fighter_kuaishou_cash.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_copy'] = 'beijing/guanshiduan/icon-copy.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_edit'] = 'beijing/dashouduan/dashoutubiaobeijing/icon-edit.jpg'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_qiepian'] = f'{ICON_FOLDER}/fighter_mine_qiepian.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_penalty_tip'] = f'{ICON_FOLDER}/fighter_mine_penalty_tip.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_kefu'] = 'beijing/tubiao/grzx_kefu.jpg'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_shangjia'] = 'beijing/tubiao/grzx_shangjia.jpg'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_punish'] = 'beijing/dashouduan/dashoutubiaobeijing/icon-punish.jpg'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_medal'] = 'beijing/dashouduan/dashoutubiaobeijing/icon-medal.jpg'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_book'] = 'beijing/dashouduan/dashoutubiaobeijing/icon-book.jpg'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_rank'] = 'beijing/dashouduan/dashoutubiaobeijing/icon-rank.jpg'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_invite'] = 'beijing/guanshiduan/icon-invite.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_contact'] = 'beijing/guanshiduan/icon-contact.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_record'] = 'beijing/guanshiduan/icon-record.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_kaohe_dafen'] = 'beijing/kaohe/daofen.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_kaohe_jilu'] = 'beijing/kaohe/jilu.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_kaohe_zhongxin'] = 'beijing/kaohe/zhongxin.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_dashou_auth'] = 'beijing/tubiao/grzx_dashou.jpg'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_clear'] = 'beijing/tubiao/grzx_qingchu.jpg'
|
||||||
|
MINIAPP_ICON_DEFAULTS['fighter_mine_switch'] = f'{ICON_FOLDER}/fighter_mine_switch.png'
|
||||||
|
MINIAPP_ICON_DEFAULTS['mine_pindao'] = 'beijing/tubiao/grzx_pindao.jpg'
|
||||||
MINIAPP_ICON_DEFAULTS['guanshi_poster_bg'] = 'beijing/haibaobeijing.jpg'
|
MINIAPP_ICON_DEFAULTS['guanshi_poster_bg'] = 'beijing/haibaobeijing.jpg'
|
||||||
MINIAPP_ICON_DEFAULTS['zuzhang_poster_bg'] = 'beijing/zuzhangbeijing.jpg'
|
MINIAPP_ICON_DEFAULTS['zuzhang_poster_bg'] = 'beijing/zuzhangbeijing.jpg'
|
||||||
|
|
||||||
@@ -73,6 +148,13 @@ POSTER_BG_DEFAULTS = {
|
|||||||
POSTER_FOLDER = 'beijing/haibao'
|
POSTER_FOLDER = 'beijing/haibao'
|
||||||
POSTER_ICON_KEYS = frozenset(POSTER_BG_FIELDS.values())
|
POSTER_ICON_KEYS = frozenset(POSTER_BG_FIELDS.values())
|
||||||
|
|
||||||
|
# 仅后台上传后才下发给小程序(页面大背景等)
|
||||||
|
CONFIG_ONLY_DELIVERY_KEYS = frozenset([
|
||||||
|
'fighter_recharge_vip_bg',
|
||||||
|
'fighter_deposit_bg',
|
||||||
|
'fighter_deposit_hero',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
def default_icon_path(icon_key: str) -> str:
|
def default_icon_path(icon_key: str) -> str:
|
||||||
return MINIAPP_ICON_DEFAULTS.get(icon_key) or f'{ICON_FOLDER}/{icon_key}.png'
|
return MINIAPP_ICON_DEFAULTS.get(icon_key) or f'{ICON_FOLDER}/{icon_key}.png'
|
||||||
@@ -81,12 +163,23 @@ def default_icon_path(icon_key: str) -> str:
|
|||||||
def get_miniapp_icons_dict(club_id: str) -> dict:
|
def get_miniapp_icons_dict(club_id: str) -> dict:
|
||||||
from config.models import ClubMiniappIcon
|
from config.models import ClubMiniappIcon
|
||||||
|
|
||||||
rows = ClubMiniappIcon.query.filter(club_id=club_id, is_active=True, is_uploaded=True)
|
rows = {
|
||||||
return {
|
r.icon_key: r
|
||||||
r.icon_key: (r.image_path or '').strip()
|
for r in ClubMiniappIcon.query.filter(club_id=club_id, is_active=True)
|
||||||
for r in rows
|
|
||||||
if r.icon_key and (r.image_path or '').strip()
|
|
||||||
}
|
}
|
||||||
|
result = {}
|
||||||
|
for key, _label in MINIAPP_ICON_META:
|
||||||
|
row = rows.get(key)
|
||||||
|
if row and row.is_uploaded and (row.image_path or '').strip():
|
||||||
|
result[key] = row.image_path.strip()
|
||||||
|
continue
|
||||||
|
if key in CONFIG_ONLY_DELIVERY_KEYS:
|
||||||
|
continue
|
||||||
|
if row and (row.image_path or '').strip():
|
||||||
|
result[key] = row.image_path.strip()
|
||||||
|
else:
|
||||||
|
result[key] = default_icon_path(key)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_pindao_payload(club_id: str) -> dict:
|
def get_pindao_payload(club_id: str) -> dict:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from backend.view import (
|
|||||||
PopupNoticeModifyAPIView,
|
PopupNoticeModifyAPIView,
|
||||||
ShgxgsjView,
|
ShgxgsjView,
|
||||||
UpdateMemberView,
|
UpdateMemberView,
|
||||||
|
MemberCardImageUploadView,
|
||||||
UpdateWithdrawSettingsView,
|
UpdateWithdrawSettingsView,
|
||||||
)
|
)
|
||||||
from users.views import KefuPunishmentListView
|
from users.views import KefuPunishmentListView
|
||||||
@@ -138,6 +139,7 @@ urlpatterns = [
|
|||||||
path('houtai/hthycatalog', ClubMemberCatalogView.as_view(), name='jituan_member_catalog'),
|
path('houtai/hthycatalog', ClubMemberCatalogView.as_view(), name='jituan_member_catalog'),
|
||||||
path('houtai/hthysj', ClubMemberEnableView.as_view(), name='jituan_member_enable'),
|
path('houtai/hthysj', ClubMemberEnableView.as_view(), name='jituan_member_enable'),
|
||||||
path('houtai/hthyxj', ClubMemberDisableView.as_view(), name='jituan_member_disable'),
|
path('houtai/hthyxj', ClubMemberDisableView.as_view(), name='jituan_member_disable'),
|
||||||
|
path('houtai/hy-card-upload', MemberCardImageUploadView.as_view(), name='jituan_member_card_upload'),
|
||||||
path('houtai/club-leixing-list', ClubShangpinLeixingListView.as_view(), name='jituan_club_leixing_list'),
|
path('houtai/club-leixing-list', ClubShangpinLeixingListView.as_view(), name='jituan_club_leixing_list'),
|
||||||
path('houtai/club-leixing-catalog', ClubShangpinLeixingCatalogView.as_view(), name='jituan_club_leixing_catalog'),
|
path('houtai/club-leixing-catalog', ClubShangpinLeixingCatalogView.as_view(), name='jituan_club_leixing_catalog'),
|
||||||
path('houtai/club-leixing-enable', ClubShangpinLeixingEnableView.as_view(), name='jituan_club_leixing_enable'),
|
path('houtai/club-leixing-enable', ClubShangpinLeixingEnableView.as_view(), name='jituan_club_leixing_enable'),
|
||||||
|
|||||||
Reference in New Issue
Block a user