客服提现列表支持明细状态筛选并补充审核相关字段。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-15 06:03:48 +08:00
parent 5a8f2099dc
commit 52e777c3a0
2 changed files with 84 additions and 39 deletions

View File

@@ -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

View File

@@ -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 '',
})