import hmac import threading import traceback import uuid import hashlib import xmltodict import time import logging import requests import os import secrets import random import string from calendar import monthrange from decimal import Decimal from datetime import date, datetime, timedelta from django.utils import timezone from django.conf import settings from django.core.exceptions import ObjectDoesNotExist from django.core.paginator import Paginator from django.db import models, transaction, IntegrityError from django.db.models import Q, Count, Sum, F, Exists, OuterRef from gvsdsdk.fluent import db, func, FQ from django.db.models.functions import TruncDate, TruncMonth, TruncYear from django.contrib.auth.hashers import make_password from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.parsers import JSONParser, MultiPartParser, FormParser # 工具类导入 from utils.oss_utils import validate_image, upload_to_oss, delete_from_oss from backend.utils import ( update_dashou_daily_by_action, 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, ) from jituan.services.club_user_access import forbid_if_user_out_of_scope, list_response_meta from shop.utils import update_dianpu_daily_stat from products.utils import update_shangpin_daily_stat from orders.notice_tasks import dingdan_guangbo from ..utils import ( verify_kefu_permission, PERMISSION_TO_SHENFEN, SHENFEN_PROFILE_MAP, has_fadan_view_permission, has_merchant_order_permission, check_fadan_permission, pick_order_id, pick_penalty_create_params, write_xiugai_log, XIUGAI_LEIXING_DASHOU, XIUGAI_LEIXING_GUANSHI, XIUGAI_LEIXING_SHANGJIA, XIUGAI_LEIXING_ZUZHANG, XIUGAI_LEIXING_LABEL, ) # models 集中导入 ## gvsdsdk RBAC 模型(使用 PascalCase 字段名,匹配实际数据库表结构) from gvsdsdk.models import Role, Permission, RolePermission, UserRole ## backend from backend.models import WithdrawalDailyStats ## users from users.models import ( UserGuanshi, UserBoss, UserZuzhang, UserKefu, UserDashou, Xiugaijilu, UserShangjia, UserShenheguan ) from users.business_models import User ## orders from orders.models import ( CommissionRate, PlayerDeliveryImage, PenaltyRecord, OrderPlayerHistory, Order, RefundRecord, MerchantOrderExt, Penalty, PenaltyAppealImage, PenaltyBonus ) ## shop from shop.models import Dianpu, DianpuMorenPeizhi, YonghuPingzheng, ShangpinLeixingDianpu, DianpuShangpinShenheShezhi ## products from products.models import ( Shangpin, ShangpinLeixing, ShangpinZhuanqu, Huiyuan, DuociFenhong, Czjilu, Huiyuangoumai, Gsfenhong ) ## config from config.models import ( WithdrawConfig, ShangjiaLianjie, AccountPermission, TixianQuotaDefault, DailyIncomeStat, DailyPayoutStat, PopupPage, PopupConfig, PopupImage ) ## rank from rank.models import ( KaoheguanBankuai, Bankuai, Chenghao, KaoheCishuFeiyong, YonghuChenghao, ShenheJilu, KaoheJiluFeiyong, KaoheJujueJilu ) # 序列化器 from ..serializers import PopupPageSerializer # 全局常量、日志对象 logger = logging.getLogger('houtai') SHOP_PRODUCT_PERMS = ['1199ab', '1199abc', '1199abd'] # 审核记录状态映射(原位于 zxkf.py,按功能组归类到考核模块) SHENHE_ZHUANGTAI_MAP = { 0: '考核中', 1: '已通过', 2: '未通过', 3: '待审核', } class KhgglView(APIView): """ 考核官管理数据接口(列表、筛选、分页) POST /houtai/khggl Body: { "phone": "管理员手机号", "page": 1, // 可选,默认1 "page_size": 15, // 可选,默认15 "yonghuid": "1234567", // 按用户ID筛选,可选 "zhuangtai": 1, // 账号状态 0=禁用,1=正常,可选 "shenhe_zhuangtai": 0, // 审核官状态 0=空闲,1=审核中,可选 "bankuai_name": "王者" // 板块名称模糊筛选,可选 } """ permission_classes = [IsAuthenticated] def post(self, request): try: username_from_frontend = request.data.get('phone', None) kefu_obj, permissions = verify_kefu_permission(request, username_from_frontend) if kefu_obj is None: return permissions if 'kaohepeizhi' not in permissions: return Response({'code': 403, 'msg': '无考核管理权限'}, status=403) # 分页参数 page = int(request.data.get('page', 1)) page_size = int(request.data.get('page_size', 15)) if page < 1: page = 1 if page_size < 1: page_size = 15 # 筛选条件 filter_yonghuid = request.data.get('yonghuid', '').strip() filter_zhuangtai = request.data.get('zhuangtai') filter_shenhe_zhuangtai = request.data.get('shenhe_zhuangtai') filter_bankuai_name = request.data.get('bankuai_name', '').strip() # 基础查询:所有审核官,预加载用户及打手扩展表 queryset = filter_user_related_by_club( UserShenheguan.query.select_related('user__DashouProfile'), request, ) if filter_yonghuid: queryset = queryset.filter(user__UserUID=filter_yonghuid) if filter_zhuangtai is not None: queryset = queryset.filter(zhuangtai=filter_zhuangtai) if filter_shenhe_zhuangtai is not None: queryset = queryset.filter(shenhe_zhuangtai=filter_shenhe_zhuangtai) # 如果填写了板块名称,筛选出关联该板块的审核官 if filter_bankuai_name: bankuai_ids = Bankuai.query.filter( mingcheng__icontains=filter_bankuai_name ).values_list('bankuai_id', flat=True) shenheguan_ids = KaoheguanBankuai.query.filter( bankuai_id__in=bankuai_ids ).values_list('kaoheguan_id', flat=True) queryset = queryset.filter(user__UserUID__in=shenheguan_ids) total = queryset.count() start = (page - 1) * page_size end = start + page_size shenheguan_list = queryset.order_by('-CreateTime')[start:end] from collections import defaultdict from jituan.services.shenhe_club import yonghu_chenghao_qs_for_request # ---------- 优化:板块打手数量(1 次 annotate 替代 2N 次循环查询)---------- # 原逻辑:每板块查 dashou 标签 ID,再统计关联的不同用户数(要求有 DashouProfile) bankuai_dashou_qs = yonghu_chenghao_qs_for_request( YonghuChenghao.query.filter( chenghao__leixing='dashou', yonghu__DashouProfile__isnull=False, ), request, ) bankuai_dashou_count_map = { item['chenghao__bankuai_id']: item['user_count'] for item in bankuai_dashou_qs.values('chenghao__bankuai_id').annotate( user_count=Count('yonghu', distinct=True) ) } # ---------- 优化:板块标签统计(1 次 annotate 替代 N*M 次循环查询)---------- # 原逻辑:每板块每标签分别统计关联的不同用户数(不要求 DashouProfile) tag_counts_qs = yonghu_chenghao_qs_for_request( YonghuChenghao.query.filter(chenghao__leixing='dashou'), request, ).values( 'chenghao_id', 'chenghao__bankuai_id', 'chenghao__mingcheng' ).annotate(user_count=Count('yonghu', distinct=True)) tags_by_bankuai = defaultdict(list) for item in tag_counts_qs: tags_by_bankuai[item['chenghao__bankuai_id']].append({ 'id': item['chenghao_id'], 'name': item['chenghao__mingcheng'], 'user_count': item['user_count'], }) all_banquai = Bankuai.query.all() bankuai_tags_data = [ { 'bankuai_id': bk.bankuai_id, 'mingcheng': bk.mingcheng, 'tags': tags_by_bankuai.get(bk.bankuai_id, []), } for bk in all_banquai ] # ---------- 优化:审核官板块关联(1 次批量查询替代 P 次循环查询)---------- shenheguan_user_uids = [sg.user.UserUID for sg in shenheguan_list] all_kgs = KaoheguanBankuai.query.filter( kaoheguan_id__in=shenheguan_user_uids ).select_related('bankuai') kg_map = defaultdict(list) for kg in all_kgs: kg_map[kg.kaoheguan_id].append(kg) # 构造返回数据(审核官列表) data_list = [] for sg in shenheguan_list: user = sg.user bankuai_info = [ { 'bankuai_id': kg.bankuai.bankuai_id, 'mingcheng': kg.bankuai.mingcheng, 'dashou_count': bankuai_dashou_count_map.get(kg.bankuai.bankuai_id, 0), } for kg in kg_map.get(user.UserUID, []) ] dashou_nick = user.DashouProfile.nicheng if hasattr(user, 'DashouProfile') and user.DashouProfile else '' data_list.append({ 'yonghuid': user.UserUID, 'avatar': user.Avatar or '', 'phone': user.Phone or '', 'zhuangtai': sg.zhuangtai, 'shenhe_zhuangtai': sg.shenhe_zhuangtai, 'shenhe_zongshu': sg.shenhe_zongshu, 'tongguo_zongshu': sg.tongguo_zongshu, 'yue': float(sg.yue), 'zonge': float(sg.zonge), 'CreateTime': sg.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if sg.CreateTime else '', 'UpdateTime': sg.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if sg.UpdateTime else '', 'bankuai': bankuai_info, 'nicheng': dashou_nick, 'is_renzheng': sg.is_renzheng, }) all_bankuai = list(Bankuai.query.values('bankuai_id', 'mingcheng')) return Response({ 'code': 0, 'msg': 'ok', 'data': { 'total': total, 'page': page, 'page_size': page_size, 'list': data_list, 'all_bankuai': all_bankuai, 'bankuai_tags': bankuai_tags_data, # 新增板块标签统计 } }) except Exception as e: logger.exception("KhgglView 接口错误") return Response({'code': 1, 'msg': f'服务器内部错误: {str(e)}'}, status=500) class ShgxgsjView(APIView): """ 审核官信息修改(余额、状态、板块关联) POST /houtai/shgxgsj """ permission_classes = [IsAuthenticated] def post(self, request): try: username_from_frontend = request.data.get('phone', None) kefu_obj, permissions = verify_kefu_permission(request, username_from_frontend) if kefu_obj is None: return permissions if 'kaohepeizhi' not in permissions: return Response({'code': 403, 'msg': '无考核管理权限'}, status=403) yonghuid = request.data.get('yonghuid') if not yonghuid: return Response({'code': 1, 'msg': '缺少用户ID'}, status=400) try: shenheguan = UserShenheguan.query.select_related('user').get(user__UserUID=yonghuid) except UserShenheguan.DoesNotExist: return Response({'code': 1, 'msg': '审核官不存在'}, status=404) from jituan.services.shenhe_club import user_belongs_to_request_club if not user_belongs_to_request_club(shenheguan.user, request): return Response({'code': 403, 'msg': '该考核官不属于当前俱乐部'}, status=403) action = request.data.get('action') if action == 'update_info': if 'yue' in request.data: shenheguan.yue = float(request.data.get('yue', 0)) if 'zhuangtai' in request.data: zt = int(request.data.get('zhuangtai')) if zt not in [0, 1]: return Response({'code': 1, 'msg': '无效的账号状态'}, status=400) shenheguan.zhuangtai = zt if 'shenhe_zhuangtai' in request.data: szt = int(request.data.get('shenhe_zhuangtai')) if szt not in [0, 1]: return Response({'code': 1, 'msg': '无效的审核官状态'}, status=400) shenheguan.shenhe_zhuangtai = szt # 新增认证状态编辑 if 'is_renzheng' in request.data: shenheguan.is_renzheng = bool(request.data.get('is_renzheng')) shenheguan.save() return Response({'code': 0, 'msg': '修改成功'}) elif action == 'add_bankuai': bankuai_id = request.data.get('bankuai_id') if not bankuai_id: return Response({'code': 1, 'msg': '缺少板块ID'}, status=400) if not Bankuai.query.filter(bankuai_id=bankuai_id).exists(): return Response({'code': 1, 'msg': '板块不存在'}, status=400) if KaoheguanBankuai.query.filter(kaoheguan_id=yonghuid, bankuai_id=bankuai_id).exists(): return Response({'code': 1, 'msg': '已关联该板块'}, status=400) KaoheguanBankuai.query.create(kaoheguan_id=yonghuid, bankuai_id=bankuai_id) return Response({'code': 0, 'msg': '板块关联成功'}) elif action == 'remove_bankuai': bankuai_id = request.data.get('bankuai_id') if not bankuai_id: return Response({'code': 1, 'msg': '缺少板块ID'}, status=400) deleted, _ = KaoheguanBankuai.query.filter( kaoheguan_id=yonghuid, bankuai_id=bankuai_id ).delete() if not deleted: return Response({'code': 1, 'msg': '未找到该板块关联'}, status=400) return Response({'code': 0, 'msg': '板块移除成功'}) else: return Response({'code': 1, 'msg': '未知操作'}, status=400) except Exception as e: logger.exception("ShgxgsjView 接口错误") return Response({'code': 1, 'msg': f'服务器内部错误: {str(e)}'}, status=500) def _batch_user_profile_map(user_uids): """批量获取用户头像、昵称、手机号""" uids = list({u for u in user_uids if u}) if not uids: return {} users = User.query.filter(UserUID__in=uids) dashou_nicks = { d.user.UserUID: d.nicheng for d in UserDashou.query.filter(user__UserUID__in=uids).select_related('user') } result = {} for u in users: result[u.UserUID] = { 'yonghuid': u.UserUID, 'avatar': u.Avatar or '', 'phone': u.Phone or '', 'nicheng': dashou_nicks.get(u.UserUID) or u.UserName or u.Phone or u.UserUID, } return result def _build_shenhe_jilu_filters(request_data): """构造 ShenheJilu 查询条件(列表与统计共用)""" qs = ShenheJilu.query.select_related('bankuai', 'chenghao') jilu_id = (request_data.get('jilu_id') or '').strip() if jilu_id: qs = qs.filter(jilu_id=jilu_id) zhuangtai = request_data.get('zhuangtai') if zhuangtai is not None and zhuangtai != '': qs = qs.filter(zhuangtai=int(zhuangtai)) assessed = request_data.get('assessed') if assessed == 'done': qs = qs.filter(zhuangtai__in=[1, 2]) elif assessed == 'undone': qs = qs.filter(zhuangtai__in=[0, 3]) bankuai_id = request_data.get('bankuai_id') if bankuai_id not in (None, ''): qs = qs.filter(bankuai_id=int(bankuai_id)) chenghao_id = request_data.get('chenghao_id') if chenghao_id not in (None, ''): qs = qs.filter(chenghao_id=int(chenghao_id)) cishu = request_data.get('cishu') if cishu not in (None, ''): qs = qs.filter(cishu=int(cishu)) dashou_kw = (request_data.get('dashou_keyword') or '').strip() if dashou_kw: dashou_uids = list( User.query.filter( Q(UserUID=dashou_kw) | Q(UserName__icontains=dashou_kw) | Q(Phone__icontains=dashou_kw) | Q(DashouProfile__nicheng__icontains=dashou_kw) ).values_list('UserUID', flat=True) ) if dashou_uids: qs = qs.filter(shenqingren_id__in=dashou_uids) else: qs = qs.none() kg_kw = (request_data.get('kaoheguan_keyword') or '').strip() if kg_kw: kg_uids = list( User.query.filter( Q(UserUID=kg_kw) | Q(UserName__icontains=kg_kw) | Q(Phone__icontains=kg_kw) | Q(DashouProfile__nicheng__icontains=kg_kw) ).values_list('UserUID', flat=True) ) if kg_uids: qs = qs.filter(shenheguan_id__in=kg_uids) else: qs = qs.none() start_time = (request_data.get('start_time') or '').strip() end_time = (request_data.get('end_time') or '').strip() if start_time: qs = qs.filter(CreateTime__gte=start_time) if end_time: qs = qs.filter(CreateTime__lte=end_time) has_kaoheguan = request_data.get('has_kaoheguan') if has_kaoheguan in (True, 'true', '1', 1): qs = qs.exclude(shenheguan_id__isnull=True).exclude(shenheguan_id='') elif has_kaoheguan in (False, 'false', '0', 0): qs = qs.filter(Q(shenheguan_id__isnull=True) | Q(shenheguan_id='')) return qs def _serialize_shenhe_jilu_row(jl, profile_map, fee_map=None, reject_count_map=None): dashou = profile_map.get(jl.shenqingren_id, { 'yonghuid': jl.shenqingren_id, 'avatar': '', 'phone': '', 'nicheng': jl.shenqingren_id, }) kaoheguan = None if jl.shenheguan_id: kaoheguan = profile_map.get(jl.shenheguan_id, { 'yonghuid': jl.shenheguan_id, 'avatar': '', 'phone': '', 'nicheng': jl.shenheguan_id, }) kaoheguan['game_id'] = jl.shenheguan_youxi_id or '' current_fee = 0.0 if fee_map is not None: current_fee = fee_map.get((jl.jilu_id, jl.cishu), 0.0) else: fd = KaoheJiluFeiyong.query.filter(jilu_id=jl.jilu_id, cishu=jl.cishu).first() if fd: current_fee = float(fd.jine) reject_count = 0 if reject_count_map is not None: reject_count = reject_count_map.get(jl.jilu_id, 0) return { 'jilu_id': jl.jilu_id, 'zhuangtai': jl.zhuangtai, 'zhuangtai_text': SHENHE_ZHUANGTAI_MAP.get(jl.zhuangtai, str(jl.zhuangtai)), 'cishu': jl.cishu, 'jiaofei_jine': float(jl.jiaofei_jine or 0), 'current_fee': current_fee, 'bankuai_id': jl.bankuai.bankuai_id if jl.bankuai else None, 'bankuai_name': jl.bankuai.mingcheng if jl.bankuai else '', 'chenghao_id': jl.chenghao.id if jl.chenghao else None, 'chenghao_name': jl.chenghao.mingcheng if jl.chenghao else '', 'chenghao_icon': jl.chenghao.tubiao_url if jl.chenghao else '', 'guize_neirong': jl.guize_neirong or '', 'dashou': { **dashou, 'game_id': jl.dashou_youxi_id or '', 'beizhu': jl.dashou_beizhu or '', }, 'kaoheguan': kaoheguan, 'reject_count': reject_count, 'CreateTime': jl.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if jl.CreateTime else '', 'UpdateTime': jl.UpdateTime.strftime('%Y-%m-%d %H:%M:%S') if jl.UpdateTime else '', } class KhjlglView(APIView): """ 考核记录列表 + 统计 POST /houtai/khjlgl """ permission_classes = [IsAuthenticated] def post(self, request): try: username_from_frontend = request.data.get('phone', None) kefu_obj, permissions = verify_kefu_permission(request, username_from_frontend) if kefu_obj is None: return permissions if 'kaohepeizhi' not in permissions: return Response({'code': 403, 'msg': '无考核管理权限'}, status=403) page = int(request.data.get('page', 1)) page_size = int(request.data.get('page_size', 20)) if page < 1: page = 1 if page_size < 1: page_size = 20 if page_size > 100: page_size = 100 from jituan.services.shenhe_club import filter_shenhe_jilu_by_request filter_data = request.data qs = filter_shenhe_jilu_by_request( _build_shenhe_jilu_filters(filter_data), request, ) # FluentQuery.filter() 会原地修改同一对象;统计与列表必须各自独立查询 stats_base = filter_shenhe_jilu_by_request( _build_shenhe_jilu_filters(filter_data), request, ) agg = stats_base.aggregate(total_fee=Sum('jiaofei_jine')) tag_rows = filter_shenhe_jilu_by_request( _build_shenhe_jilu_filters(filter_data), request, ).values( 'chenghao_id', 'chenghao__mingcheng' ).annotate( total=Count('jilu_id'), passed=Count('jilu_id', filter=Q(zhuangtai=1)), failed=Count('jilu_id', filter=Q(zhuangtai=2)), in_progress=Count('jilu_id', filter=Q(zhuangtai=0)), pending=Count('jilu_id', filter=Q(zhuangtai=3)), ).order_by('-total') _stats_agg = stats_base.aggregate( total=Count('id'), passed=Count('id', filter=Q(zhuangtai=1)), failed=Count('id', filter=Q(zhuangtai=2)), in_progress=Count('id', filter=Q(zhuangtai=0)), pending=Count('id', filter=Q(zhuangtai=3)), ) stats = { 'total': _stats_agg['total'], 'passed': _stats_agg['passed'], 'failed': _stats_agg['failed'], 'in_progress': _stats_agg['in_progress'], 'pending': _stats_agg['pending'], 'total_fee': float(agg['total_fee'] or 0), 'tag_stats': [ { 'chenghao_id': r['chenghao_id'], 'chenghao_name': r['chenghao__mingcheng'] or '未知标签', 'total': r['total'], 'passed': r['passed'], 'failed': r['failed'], 'in_progress': r['in_progress'], 'pending': r['pending'], } for r in tag_rows if r['chenghao_id'] ], } total = qs.count() start = (page - 1) * page_size rows = qs.order_by('-CreateTime')[start:start + page_size].to_list() uids = [] jilu_ids = [] for jl in rows: uids.append(jl.shenqingren_id) if jl.shenheguan_id: uids.append(jl.shenheguan_id) jilu_ids.append(jl.jilu_id) profile_map = _batch_user_profile_map(uids) fee_pairs = [(jl.jilu_id, jl.cishu) for jl in rows] fee_map = {} if fee_pairs: jids = [p[0] for p in fee_pairs] for fd in KaoheJiluFeiyong.query.filter(jilu_id__in=jids): fee_map[(fd.jilu_id, fd.cishu)] = float(fd.jine) reject_counts = { r['jilu_id']: r['cnt'] for r in KaoheJujueJilu.query.filter(jilu_id__in=jilu_ids) .values('jilu_id') .annotate(cnt=Count('id')) .all() } if jilu_ids else {} data_list = [ _serialize_shenhe_jilu_row(jl, profile_map, fee_map, reject_counts) for jl in rows ] all_bankuai = list(Bankuai.query.values('bankuai_id', 'mingcheng')) all_tags = list( Chenghao.query.filter(leixing='dashou') .values('id', 'mingcheng', 'bankuai_id') .order_by('mingcheng') ) return Response({ 'code': 0, 'msg': 'ok', 'data': { 'total': total, 'page': page, 'page_size': page_size, 'list': data_list, 'stats': stats, 'all_bankuai': all_bankuai, 'all_tags': all_tags, }, }) except Exception as e: logger.exception('KhjlglView 接口错误') return Response({'code': 1, 'msg': f'服务器内部错误: {str(e)}'}, status=500) class KhjlczView(APIView): """ 考核记录操作 / 详情 POST /houtai/khjlcz action: - get_detail: 获取单条详情(含缴费明细、拒绝历史) - to_pending: 考核中 → 待审核(取消指定考核官,与小程序 transfer 一致) """ permission_classes = [IsAuthenticated] def post(self, request): try: username_from_frontend = request.data.get('phone', None) kefu_obj, permissions = verify_kefu_permission(request, username_from_frontend) if kefu_obj is None: return permissions if 'kaohepeizhi' not in permissions: return Response({'code': 403, 'msg': '无考核管理权限'}, status=403) action = request.data.get('action') jilu_id = (request.data.get('jilu_id') or '').strip() if not jilu_id: return Response({'code': 1, 'msg': '缺少记录ID'}, status=400) if action == 'get_detail': try: jl = ShenheJilu.query.select_related('bankuai', 'chenghao').get(jilu_id=jilu_id) except ShenheJilu.DoesNotExist: return Response({'code': 1, 'msg': '记录不存在'}, status=404) uids = [jl.shenqingren_id] if jl.shenheguan_id: uids.append(jl.shenheguan_id) profile_map = _batch_user_profile_map(uids) fee_list = [ { 'cishu': f.cishu, 'jine': float(f.jine), } for f in KaoheJiluFeiyong.query.filter(jilu_id=jilu_id).order_by('cishu') ] reject_list = [] _reject_records = list(KaoheJujueJilu.query.filter(jilu_id=jilu_id).order_by('-CreateTime')) _kg_ids = [r.shenheguan_id for r in _reject_records if r.shenheguan_id] _kg_prof_map = _batch_user_profile_map(_kg_ids) if _kg_ids else {} for r in _reject_records: kg_prof = _kg_prof_map.get(r.shenheguan_id, {}) reject_list.append({ 'cishu': r.cishu, 'shenheguan_id': r.shenheguan_id, 'shenheguan_nicheng': kg_prof.get('nicheng', r.shenheguan_id), 'yuanyin': r.yuanyin, 'CreateTime': r.CreateTime.strftime('%Y-%m-%d %H:%M:%S') if r.CreateTime else '', }) record = _serialize_shenhe_jilu_row(jl, profile_map) record['fee_list'] = fee_list record['reject_list'] = reject_list return Response({'code': 0, 'msg': 'ok', 'data': record}) if action == 'to_pending': with transaction.atomic(): jl = ShenheJilu.objects.select_for_update().filter(jilu_id=jilu_id).first() if not jl: return Response({'code': 1, 'msg': '记录不存在'}, status=404) if jl.zhuangtai != 0: return Response({'code': 1, 'msg': '仅「考核中」的记录可退回待审核'}, status=400) old_kg_id = jl.shenheguan_id jl.shenheguan_id = None jl.shenheguan_youxi_id = None jl.zhuangtai = 3 jl.save(update_fields=['shenheguan_id', 'shenheguan_youxi_id', 'zhuangtai', 'UpdateTime']) if old_kg_id: UserShenheguan.query.filter(user__UserUID=old_kg_id).update(shenhe_zhuangtai=0) return Response({'code': 0, 'msg': '已退回待审核,考核官指定已取消'}) return Response({'code': 1, 'msg': '无效的操作类型'}, status=400) except Exception as e: logger.exception('KhjlczView 接口错误') return Response({'code': 1, 'msg': f'服务器内部错误: {str(e)}'}, status=500)