From 52e777c3a00dba9f247a3b6ea0a6faa65610725b Mon Sep 17 00:00:00 2001 From: XingQue Date: Wed, 15 Jul 2026 06:03:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A2=E6=9C=8D=E6=8F=90=E7=8E=B0=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E6=94=AF=E6=8C=81=E6=98=8E=E7=BB=86=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=AD=9B=E9=80=89=E5=B9=B6=E8=A1=A5=E5=85=85=E5=AE=A1=E6=A0=B8?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=AD=97=E6=AE=B5=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- yonghu/tixian_shenhe_services.py | 20 +++++- yonghu/views.py | 103 ++++++++++++++++++++----------- 2 files changed, 84 insertions(+), 39 deletions(-) diff --git a/yonghu/tixian_shenhe_services.py b/yonghu/tixian_shenhe_services.py index c515e8b..3526f9b 100644 --- a/yonghu/tixian_shenhe_services.py +++ b/yonghu/tixian_shenhe_services.py @@ -115,18 +115,34 @@ def load_audit_dakuan_mode_map(audit_ids): def load_audit_meta_map(audit_ids): """ 批量取审核表元数据(供后台列表等) - 返回 {审核记录id: {'dakuan_mode': int, 'shenhe_danhao': str}} + 返回 {审核记录id: {dakuan_mode, shenhe_danhao, shouxufei, shijidaozhang, ...}} """ if not audit_ids: return {} - value_fields = ['id', 'shenhe_danhao'] + value_fields = [ + 'id', 'shenhe_danhao', + 'shouxufei', 'shijidaozhang', 'feilv', + 'fail_reason', 'bhliyou', 'tixian_auto_id', 'zhuangtai', + ] if has_dakuan_mode_field(): value_fields.append('dakuan_mode') + # dakuan_mch_id 迁移后才有 + if any(f.name == 'dakuan_mch_id' for f in TixianShenheJilu._meta.fields): + value_fields.append('dakuan_mch_id') + result = {} for row in TixianShenheJilu.objects.filter(id__in=audit_ids).values(*value_fields): result[row['id']] = { 'shenhe_danhao': row.get('shenhe_danhao') or '', 'dakuan_mode': row.get('dakuan_mode', DAKUAN_MODE_AUTO), + 'shouxufei': str(row['shouxufei']) if row.get('shouxufei') is not None else '', + 'shijidaozhang': str(row['shijidaozhang']) if row.get('shijidaozhang') is not None else '', + 'feilv': str(row['feilv']) if row.get('feilv') is not None else '', + 'fail_reason': row.get('fail_reason') or '', + 'bhliyou': row.get('bhliyou') or '', + 'tixian_auto_id': row.get('tixian_auto_id') or '', + 'dakuan_mch_id': row.get('dakuan_mch_id') or '', + 'audit_zhuangtai': row.get('zhuangtai'), } return result diff --git a/yonghu/views.py b/yonghu/views.py index 3cb320e..c7602b0 100644 --- a/yonghu/views.py +++ b/yonghu/views.py @@ -11676,28 +11676,15 @@ class KefuWithdrawListView(APIView): "phone": "客服手机号", "page": 1, "page_size": 20, - "status": 1(待审核)/2(已处理), - "type": 1(打手佣金)/2(管事分红)/3(组长分红)/4(审核官分佣)/5(打手押金)/6(商家余额), 可选 + "status": 1(待审核)/2(已处理), # 未传 zhuangtai 时生效 + "zhuangtai": 1~6, # 明细状态精确筛选,传入时优先于 status + "type": 1~6 可选, "payment": 1(微信)/2(支付宝) 可选, "search_uid": "用户ID搜索" 可选, "date": "YYYY-MM-DD" 可选, - "min_amount": 0, # 最小提现金额(元)可选 - "max_amount": 999999, # 最大提现金额(元)可选 - "dakuan_mode": 1 # 打款方式:1手动打款 2自动打款,可选 - } - 认证:JWT - 返回:{ - "code": 0, - "data": { - "list": [提现记录], - "total": 总数, - "stats": { - "total": 总记录数, - "awaiting": 待审核数, - "processed": 已处理数, - "total_amount": "总金额(元)" - } - } + "min_amount": 0, + "max_amount": 999999, + "dakuan_mode": 1手动/2自动 可选 } """ permission_classes = [IsAuthenticated] @@ -11757,6 +11744,7 @@ class KefuWithdrawListView(APIView): page_size = min(max(page_size, 1), 100) status_filter = request.data.get('status') + zhuangtai_filter = request.data.get('zhuangtai') type_filter = request.data.get('type') payment_filter = request.data.get('payment') search_uid = (request.data.get('search_uid') or '').strip() @@ -11774,13 +11762,22 @@ class KefuWithdrawListView(APIView): if '005bb' not in permissions: return Response({'code': 403, 'msg': '您无权查看平台订单列表'}) - q = Q() - try: status_val = int(status_filter) if status_filter is not None and str(status_filter).strip() != '' else None except (TypeError, ValueError): status_val = None + try: + zhuangtai_val = ( + int(zhuangtai_filter) + if zhuangtai_filter is not None and str(zhuangtai_filter).strip() != '' + else None + ) + except (TypeError, ValueError): + zhuangtai_val = None + if zhuangtai_val is not None and zhuangtai_val not in (1, 2, 3, 4, 5, 6): + return Response({'code': 400, 'msg': 'zhuangtai 仅支持 1~6'}) + try: dakuan_mode_val = int(dakuan_mode_filter) if dakuan_mode_filter is not None and str(dakuan_mode_filter).strip() != '' else None except (TypeError, ValueError): @@ -11789,14 +11786,7 @@ class KefuWithdrawListView(APIView): # 未传打款方式参数 → 默认手动打款(1) effective_dakuan = dakuan_mode_val if dakuan_mode_val in (1, 2) else 1 - if status_val == 1: - q &= Q(zhuangtai=1) - elif status_val == 2: - if effective_dakuan == 2: - q &= Q(zhuangtai__in=[2, 3, 4, 5, 6]) - else: - q &= Q(zhuangtai__in=[2, 3]) - + q = Q() if type_filter is not None and str(type_filter).strip() != '': try: type_val = int(type_filter) @@ -11843,25 +11833,52 @@ class KefuWithdrawListView(APIView): 'data': { 'list': [], 'total': 0, - 'stats': {'total': 0, 'awaiting': 0, 'processed': 0, 'total_amount': '0.00'}, + 'stats': { + 'total': 0, 'awaiting': 0, 'processed': 0, + 'pending_collect': 0, 'success': 0, 'fail': 0, + 'total_amount': '0.00', + }, }, }) processed_statuses = [2, 3, 4, 5, 6] if effective_dakuan == 2 else [2, 3] - base_qs = self._list_queryset(q, shenhe_field_ok) - total_count = base_qs.count() - awaiting_count = self._list_queryset(q & Q(zhuangtai=1), shenhe_field_ok).count() + # 统计用:不含明细/粗粒度状态,便于顶栏卡片在任意页可用 + q_for_stats = q + awaiting_count = self._list_queryset(q_for_stats & Q(zhuangtai=1), shenhe_field_ok).count() processed_count = self._list_queryset( - q & Q(zhuangtai__in=processed_statuses), shenhe_field_ok, + q_for_stats & Q(zhuangtai__in=processed_statuses), shenhe_field_ok, ).count() + pending_collect_count = self._list_queryset( + q_for_stats & Q(zhuangtai=6), shenhe_field_ok, + ).count() if effective_dakuan == 2 else 0 + success_count = self._list_queryset(q_for_stats & Q(zhuangtai=2), shenhe_field_ok).count() + fail_count = self._list_queryset( + q_for_stats & Q(zhuangtai__in=([3, 5] if effective_dakuan == 2 else [3])), + shenhe_field_ok, + ).count() + stats_total = self._list_queryset(q_for_stats, shenhe_field_ok).count() + + # 列表用:明细状态优先;否则粗粒度 status + q_list = q + if zhuangtai_val is not None: + q_list &= Q(zhuangtai=zhuangtai_val) + elif status_val == 1: + q_list &= Q(zhuangtai=1) + elif status_val == 2: + q_list &= Q(zhuangtai__in=processed_statuses) + + base_qs = self._list_queryset(q_list, shenhe_field_ok) agg = base_qs.aggregate(total=Sum('jine')) total_amount = agg.get('total') or 0 stats = { - 'total': total_count, + 'total': stats_total, 'awaiting': awaiting_count, 'processed': processed_count, + 'pending_collect': pending_collect_count, + 'success': success_count, + 'fail': fail_count, 'total_amount': str(round(float(total_amount), 2)), } @@ -11891,8 +11908,10 @@ class KefuWithdrawListView(APIView): for item in records: shenhe_jilu_id = getattr(item, 'shenhe_jilu_id', None) if shenhe_field_ok else None shenhe_danhao = (getattr(item, 'shenhe_danhao', None) or '') if shenhe_field_ok else '' + audit_meta = audit_meta_map.get(shenhe_jilu_id, {}) if shenhe_jilu_id else {} if shenhe_jilu_id and not shenhe_danhao: - shenhe_danhao = audit_meta_map.get(shenhe_jilu_id, {}).get('shenhe_danhao', '') + shenhe_danhao = audit_meta.get('shenhe_danhao', '') + fail_reason = audit_meta.get('fail_reason') or '' list_data.append({ 'id': item.id, 'shenhe_jilu_id': shenhe_jilu_id, @@ -11906,10 +11925,20 @@ class KefuWithdrawListView(APIView): 'skzhanghao': item.skzhanghao or '', 'jine': str(item.jine) if item.jine is not None else '0.00', 'zhuangtai': item.zhuangtai, + 'zhuangtai_text': { + 1: '审核中', 2: '提现成功', 3: '提现失败', + 4: '审核成功', 5: '审核失败', 6: '待收款', + }.get(item.zhuangtai, '未知'), 'fangshi': item.fangshi, 'dakuan_mode': self._resolve_row_dakuan_mode(item, audit_mode_map, shenhe_field_ok), 'shenheid': item.shenheid or '', - 'bhliyou': item.bhliyou or '', + 'bhliyou': item.bhliyou or audit_meta.get('bhliyou') or '', + 'fail_reason': fail_reason, + 'shouxufei': audit_meta.get('shouxufei') or '', + 'shijidaozhang': audit_meta.get('shijidaozhang') or '', + 'feilv': audit_meta.get('feilv') or '', + 'dakuan_mch_id': audit_meta.get('dakuan_mch_id') or '', + 'tixian_auto_id': audit_meta.get('tixian_auto_id') or '', 'create_time': item.create_time.strftime('%Y-%m-%d %H:%M:%S') if item.create_time else '', 'update_time': item.update_time.strftime('%Y-%m-%d %H:%M:%S') if item.update_time else '', })