feat: 只看审核按俱乐部隔离,商品管理支持俱乐部视图

未绑店出货开关按 club_id 配置;后台商品列表可在具体小程序下管理并切换审核展示。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-21 03:20:03 +08:00
parent ed627fa6f7
commit 6515568ec0
9 changed files with 249 additions and 42 deletions

View File

@@ -142,14 +142,24 @@ class GetProductBaseDataView(APIView):
if '2200a' not in permissions:
return Response({'code': 403, 'msg': '无权限管理商品'})
# 获取所有商品类型(按 paixu 升序)
# 获取所有商品类型(按 paixu 升序);商品数按当前俱乐部统计
from jituan.services.club_context import filter_club_char_field, resolve_club_scope
from jituan.constants import DATA_SCOPE_ALL
from jituan.services.club_write import resolve_club_id_for_write
from shop.services.shenhe_config import get_or_create_shenhe_config, is_zhi_kan_shenhe_enabled
type_qs = ShangpinLeixing.query.all().order_by('paixu')
# 批量聚合商品数量,避免循环内 N+1 count
# 批量聚合商品数量,避免循环内 N+1 count(按俱乐部)
_public_sp = filter_club_char_field(
Shangpin.query.filter(
dianpu__isnull=True, dianpu_leixing__isnull=True, leixing_id__isnull=False
),
request,
field='club_id',
)
_type_counts = {
item['leixing_id']: item['cnt']
for item in Shangpin.query.filter(
dianpu__isnull=True, dianpu_leixing__isnull=True, leixing_id__isnull=False
).values('leixing_id').annotate(cnt=Count('id'))
for item in _public_sp.values('leixing_id').annotate(cnt=Count('id'))
}
type_list = []
for t in type_qs:
@@ -164,7 +174,6 @@ class GetProductBaseDataView(APIView):
})
# 获取专区(按俱乐部隔离;集团汇总看全部)
from jituan.services.club_context import filter_club_char_field
zone_qs = filter_club_char_field(
ShangpinZhuanqu.query.all().order_by('paixu'), request, field='club_id'
)
@@ -194,12 +203,24 @@ class GetProductBaseDataView(APIView):
# 获取所有会员(只需 ID、介绍、价格
member_list = list(Huiyuan.query.all().values('huiyuan_id', 'jieshao', 'jiage'))
# 本俱乐部「只看审核」开关(集团汇总不下发可写状态)
club_scoped = resolve_club_scope(request) != DATA_SCOPE_ALL
zhi_kan_shenhe = True
club_id = ''
if club_scoped:
club_id = resolve_club_id_for_write(request) or ''
get_or_create_shenhe_config(club_id)
zhi_kan_shenhe = is_zhi_kan_shenhe_enabled(club_id)
return Response({
'code': 0,
'data': {
'type_list': type_list,
'zone_list': zone_list,
'member_list': member_list,
'zhi_kan_shenhe': zhi_kan_shenhe,
'club_scoped': club_scoped,
'club_id': club_id,
}
})
@@ -701,6 +722,14 @@ class AddProductView(APIView):
zhuanqu_obj = ShangpinZhuanqu.query.get(id=zhuanqu_id)
if zhuanqu_obj.leixing_id != leixing_id:
return Response({'code': 400, 'msg': '专区不属于该商品类型'})
from jituan.constants import DATA_SCOPE_ALL
from jituan.services.club_context import resolve_club_scope
from jituan.services.club_write import resolve_club_id_for_write
if resolve_club_scope(request) != DATA_SCOPE_ALL:
write_club = resolve_club_id_for_write(request)
zone_club = getattr(zhuanqu_obj, 'club_id', None) or 'xq'
if zone_club != write_club:
return Response({'code': 400, 'msg': '专区不属于当前俱乐部,请先切换俱乐部或选择本俱乐部专区'})
except ShangpinZhuanqu.DoesNotExist:
return Response({'code': 400, 'msg': '商品专区不存在'})
@@ -1134,6 +1163,52 @@ class UpdateProductView(APIView):
return Response({'code': 0, 'msg': '商品修改成功', 'data': {'id': product.id}})
class UpdateZhiKanShenheView(APIView):
"""
商品管理页:按俱乐部更新「只看审核商品」开关。
权限2200a
POST /houtai/htxgzhikan
"""
permission_classes = []
parser_classes = [JSONParser]
def post(self, request):
username = request.data.get('username', '').strip()
if not username:
return Response({'code': 401, 'msg': '缺少username'})
kefu, permissions = verify_kefu_permission(request, username)
if kefu is None:
return permissions
if '2200a' not in permissions:
return Response({'code': 403, 'msg': '无权限管理商品'})
val = request.data.get('zhi_kan_shenhe')
if val is None:
return Response({'code': 400, 'msg': '缺少参数 zhi_kan_shenhe'})
from jituan.constants import DATA_SCOPE_ALL
from jituan.services.club_context import resolve_club_scope
from jituan.services.club_write import resolve_club_id_for_write
from shop.services.shenhe_config import get_or_create_shenhe_config
if resolve_club_scope(request) == DATA_SCOPE_ALL:
return Response({'code': 400, 'msg': '请先切换到具体俱乐部再修改只看审核开关'})
try:
with transaction.atomic():
club_id = resolve_club_id_for_write(request)
config = get_or_create_shenhe_config(club_id)
config = DianpuShangpinShenheShezhi.objects.select_for_update().get(pk=config.pk)
config.zhi_kan_shenhe = bool(val)
config.save(update_fields=['zhi_kan_shenhe'])
return Response({
'code': 0,
'msg': '只看审核开关已更新',
'data': {'club_id': club_id, 'zhi_kan_shenhe': bool(val)},
})
except Exception:
logging.getLogger(__name__).exception('更新只看审核开关失败')
return Response({'code': 500, 'msg': '服务器错误'})

View File

@@ -421,17 +421,38 @@ class ShopPublicTypeAndAuditView(APIView):
logger.exception("查询公共商品类型失败")
return Response({'code': 500, 'msg': '服务器错误,请稍后重试'})
# ---------- 获取审核模式配置 ----------
audit_config = DianpuShangpinShenheShezhi.query.filter(id=1).first()
kaiqi_shenhe = audit_config.kaiqi_shenhe if audit_config else False
zhi_kan_shenhe = getattr(audit_config, 'zhi_kan_shenhe', True) if audit_config else True
# ---------- 获取本俱乐部审核模式配置 ----------
from jituan.services.club_write import resolve_club_id_for_write
from shop.services.shenhe_config import get_or_create_shenhe_config
from jituan.constants import DATA_SCOPE_ALL
from jituan.services.club_context import resolve_club_scope
if resolve_club_scope(request) == DATA_SCOPE_ALL:
# 集团汇总:不自动创建,返回默认值提示前端切到具体俱乐部
return Response({
'code': 0,
'data': {
'public_types': type_list,
'kaiqi_shenhe': False,
'zhi_kan_shenhe': True,
'club_scoped': False,
'msg': '请切换到具体俱乐部查看/修改审核展示开关',
}
})
club_id = resolve_club_id_for_write(request)
audit_config = get_or_create_shenhe_config(club_id)
kaiqi_shenhe = audit_config.kaiqi_shenhe
zhi_kan_shenhe = bool(getattr(audit_config, 'zhi_kan_shenhe', True))
return Response({
'code': 0,
'data': {
'public_types': type_list,
'kaiqi_shenhe': kaiqi_shenhe,
'zhi_kan_shenhe': bool(zhi_kan_shenhe),
'zhi_kan_shenhe': zhi_kan_shenhe,
'club_id': club_id,
'club_scoped': True,
}
})
@@ -640,18 +661,28 @@ class ShopProductModifyView(APIView):
if kaiqi is None:
return Response({'code': 400, 'msg': '缺少参数 kaiqi_shenhe'})
from jituan.constants import DATA_SCOPE_ALL
from jituan.services.club_context import resolve_club_scope
from jituan.services.club_write import resolve_club_id_for_write
from shop.services.shenhe_config import get_or_create_shenhe_config
if resolve_club_scope(request) == DATA_SCOPE_ALL:
return Response({'code': 400, 'msg': '请先切换到具体俱乐部再修改审核模式'})
try:
config, _ = DianpuShangpinShenheShezhi.objects.select_for_update().get_or_create(id=1)
club_id = resolve_club_id_for_write(request)
config = get_or_create_shenhe_config(club_id)
config = DianpuShangpinShenheShezhi.objects.select_for_update().get(pk=config.pk)
config.kaiqi_shenhe = bool(kaiqi)
config.save(update_fields=['kaiqi_shenhe'])
return Response({'code': 0, 'msg': '审核模式已更新'})
return Response({'code': 0, 'msg': '审核模式已更新', 'data': {'club_id': club_id}})
except Exception as e:
logger.exception("更新审核模式失败")
return Response({'code': 500, 'msg': '服务器错误'})
@transaction.atomic
def _update_zhi_kan_shenhe(self, request, user_perms):
"""点单端:未绑店用户是否按身份只看审核专用商品。"""
"""点单端:未绑店用户是否按身份只看审核专用商品(按俱乐部)"""
if not has_perm_code(user_perms, '1199ab'):
return Response({'code': 403, 'msg': '无权限修改只看审核开关'})
@@ -659,11 +690,21 @@ class ShopProductModifyView(APIView):
if val is None:
return Response({'code': 400, 'msg': '缺少参数 zhi_kan_shenhe'})
from jituan.constants import DATA_SCOPE_ALL
from jituan.services.club_context import resolve_club_scope
from jituan.services.club_write import resolve_club_id_for_write
from shop.services.shenhe_config import get_or_create_shenhe_config
if resolve_club_scope(request) == DATA_SCOPE_ALL:
return Response({'code': 400, 'msg': '请先切换到具体俱乐部再修改只看审核开关'})
try:
config, _ = DianpuShangpinShenheShezhi.objects.select_for_update().get_or_create(id=1)
club_id = resolve_club_id_for_write(request)
config = get_or_create_shenhe_config(club_id)
config = DianpuShangpinShenheShezhi.objects.select_for_update().get(pk=config.pk)
config.zhi_kan_shenhe = bool(val)
config.save(update_fields=['zhi_kan_shenhe'])
return Response({'code': 0, 'msg': '只看审核开关已更新'})
return Response({'code': 0, 'msg': '只看审核开关已更新', 'data': {'club_id': club_id}})
except Exception:
logger.exception("更新只看审核开关失败")
return Response({'code': 500, 'msg': '服务器错误'})