diff --git a/backend/view.py b/backend/view.py index d6877d7..89cec94 100644 --- a/backend/view.py +++ b/backend/view.py @@ -39,6 +39,7 @@ from backend.utils import ( update_shangjia_daily ) from jituan.services.club_context import filter_club_char_field, filter_queryset_by_club, filter_user_related_by_club, filter_user_qs_by_club, orders_for_request +from jituan.services.catalog_scope import block_non_group_catalog_scope from jituan.services.club_penalty import ( filter_penalty_qs, resolve_penalty_club_id, filter_gsfenhong_qs, forbid_penalty_out_of_scope, resolve_penalty_record_club_id, @@ -1766,6 +1767,9 @@ class GetProductBaseDataView(APIView): return permissions if '2200a' not in permissions: return Response({'code': 403, 'msg': '无权限管理商品'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) # 获取所有商品类型(按 paixu 升序) type_qs = ShangpinLeixing.query.all().order_by('paixu') @@ -1854,6 +1858,9 @@ class GetProductListView(APIView): return permissions if '2200a' not in permissions: return Response({'code': 403, 'msg': '无权限管理商品'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) # 获取参数 leixing_id = request.data.get('leixing_id') @@ -1981,6 +1988,9 @@ class GetProductListView(APIView): return permissions if '2200a' not in permissions: return Response({'code': 403, 'msg': '无权限管理商品'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) # 获取所有商品类型(按 paixu 升序) type_qs = ShangpinLeixing.query.all().order_by('paixu') @@ -2059,6 +2069,9 @@ class GetProductListView(APIView): return permissions if '2200a' not in permissions: return Response({'code': 403, 'msg': '无权限管理商品'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) # 获取参数 leixing_id = request.data.get('leixing_id') @@ -2180,6 +2193,9 @@ class SaveProductOrderView(APIView): return permissions if '2200a' not in permissions: return Response({'code': 403, 'msg': '无权限管理商品'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) sort_type = request.data.get('type', '').strip().lower() if sort_type not in ('leixing', 'zhuanqu'): @@ -2242,6 +2258,9 @@ class AddProductView(APIView): return permissions if '2200a' not in permissions: return Response({'code': 403, 'msg': '无权限管理商品'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) # 获取表单字段 biaoqian = request.data.get('biaoqian', '').strip() @@ -2439,6 +2458,9 @@ class DeleteProductView(APIView): return permissions if '2200a' not in permissions: return Response({'code': 403, 'msg': '无权限管理商品'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) # 查询商品是否存在 try: @@ -2501,6 +2523,9 @@ class GetProductDetailView(APIView): return permissions if '2200a' not in permissions: return Response({'code': 403, 'msg': '无权限管理商品'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) # 查询商品 try: @@ -2582,6 +2607,9 @@ class UpdateProductView(APIView): return permissions if '2200a' not in permissions: return Response({'code': 403, 'msg': '无权限管理商品'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) # 使用事务,将 select_for_update 放在事务内 with transaction.atomic(): @@ -4515,6 +4543,9 @@ class GetProductTypeZoneView(APIView): return permissions if '7007a' not in permissions: return Response({'code': 403, 'msg': '您无权访问此页面'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) # 查询所有商品类型(含专区数量) types = ShangpinLeixing.query.all().order_by('-paixu') # paixu 越大越靠前 @@ -4592,6 +4623,9 @@ class ModifyProductTypeZoneView(APIView): return permissions if '7007a' not in permissions: return Response({'code': 403, 'msg': '您无权进行此操作'}) + scope_err = block_non_group_catalog_scope(request) + if scope_err: + return Response({'code': 400, 'msg': scope_err}) if obj_type == 'leixing': return self.handle_leixing(request, action) diff --git a/jituan/services/catalog_scope.py b/jituan/services/catalog_scope.py new file mode 100644 index 0000000..13ce76b --- /dev/null +++ b/jituan/services/catalog_scope.py @@ -0,0 +1,15 @@ +"""集团全局商品目录(商品/类型/专区)须在集团汇总视图操作。""" +from jituan.constants import DATA_SCOPE_ALL +from jituan.services.club_context import resolve_club_scope + +GROUP_CATALOG_SCOPE_MSG = ( + '商品、类型与专区为集团全局数据,请在顶栏切换为「集团汇总(全部子公司)」后操作;' + '具体小程序仅可在「小程序配置」中做上架/图标等俱乐部侧配置。' +) + + +def block_non_group_catalog_scope(request): + """非集团汇总视图时返回错误文案,否则返回 None。""" + if resolve_club_scope(request) != DATA_SCOPE_ALL: + return GROUP_CATALOG_SCOPE_MSG + return None diff --git a/jituan/services/dashou_exam.py b/jituan/services/dashou_exam.py index 2868657..9b6cc7f 100644 --- a/jituan/services/dashou_exam.py +++ b/jituan/services/dashou_exam.py @@ -8,6 +8,7 @@ from django.utils import timezone from jituan.constants import DATA_SCOPE_ALL from jituan.models import ( + Club, ClubDashouExamConfig, ClubDashouExamPass, ClubDashouExamQuestion, @@ -200,6 +201,31 @@ def mark_exam_passed(request, user): return {'club_id': club_id, 'passed': True}, None +def build_group_exam_overview(request): + """集团汇总视图:各俱乐部考试配置一览。""" + if not _scope_blocked(request): + return None, '请在集团汇总视图查看各俱乐部概览' + rows = [] + for club in Club.query.filter(status=1).order_by('club_id'): + cid = club.club_id + cfg = get_or_create_config(cid) + pool = ClubDashouExamQuestion.query.filter(club_id=cid).count() + enabled_pool = ClubDashouExamQuestion.query.filter(club_id=cid, is_enabled=True).count() + passed_count = ClubDashouExamPass.query.filter(club_id=cid).count() + rows.append({ + 'club_id': cid, + 'club_name': club.name or cid, + 'is_enabled': bool(cfg.is_enabled), + 'draw_count': int(cfg.draw_count or 10), + 'pass_count': int(cfg.pass_count or 10), + 'require_member': bool(cfg.require_member), + 'pool_count': pool, + 'enabled_pool_count': enabled_pool, + 'passed_user_count': passed_count, + }) + return {'list': rows}, None + + def build_admin_config_payload(request): if _scope_blocked(request): return {'scope_error': SCOPE_MSG} diff --git a/jituan/views_dashou_exam.py b/jituan/views_dashou_exam.py index 9d566d9..f387f93 100644 --- a/jituan/views_dashou_exam.py +++ b/jituan/views_dashou_exam.py @@ -61,7 +61,16 @@ class DashouExamConfigAdminView(APIView): if EXAM_PERM not in permissions: return Response({'code': 403, 'msg': '无权限'}) action = (request.data.get('action') or 'get').strip() - from jituan.services.dashou_exam import build_admin_config_payload, save_admin_config + from jituan.services.dashou_exam import ( + build_admin_config_payload, + build_group_exam_overview, + save_admin_config, + ) + if action == 'overview': + data, err = build_group_exam_overview(request) + if err: + return Response({'code': 400, 'msg': err}) + return Response({'code': 0, 'data': data}) if action == 'save': data, err = save_admin_config(request, request.data) if err: