From 993c0c54b02bdc899c52e0744e52e9409b3fc09e Mon Sep 17 00:00:00 2001 From: XingQue Date: Sat, 20 Jun 2026 04:12:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E5=AE=A2=E6=9C=8D?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=BB=9F=E8=AE=A1=EF=BC=8C=E5=BC=BA=E5=8C=96?= =?UTF-8?q?=E4=BA=86=E5=95=86=E5=AE=B6=E6=95=B0=E6=8D=AE=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=8E=B7=E5=8F=96=E6=9B=B4=E5=A4=9A=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- merchant_ops/services/order_enrich.py | 86 +++++++++++++++++++++++++++ merchant_ops/views_manage.py | 39 ++++++++---- merchant_ops/views_orders.py | 12 +++- orders/views.py | 6 ++ 4 files changed, 131 insertions(+), 12 deletions(-) create mode 100644 merchant_ops/services/order_enrich.py diff --git a/merchant_ops/services/order_enrich.py b/merchant_ops/services/order_enrich.py new file mode 100644 index 0000000..491c057 --- /dev/null +++ b/merchant_ops/services/order_enrich.py @@ -0,0 +1,86 @@ +"""订单响应增强:派单客服信息、头像相对路径。""" +from merchant_ops.constants import ACTOR_MERCHANT, ACTOR_STAFF +from merchant_ops.models import MerchantOrderDispatch, MerchantStaffMember +from users.business_models import User + + +def user_avatar_relative(user): + """返回用户表 Avatar 相对路径(前端自行拼接 OSS)。""" + if not user: + return '' + av = (getattr(user, 'Avatar', None) or '').strip() + if not av: + return '' + if av.startswith('http://') or av.startswith('https://'): + return av + return av.lstrip('/') + + +def get_user_avatar_by_uid(uid): + if not uid: + return '' + u = User.query.filter(UserUID=uid).first() + return user_avatar_relative(u) + + +def get_dispatch_staff_payload(order_id): + """订单派单归属;无记录则 None(商家老板派单可能无 dispatch 记录)。""" + if not order_id: + return None + disp = MerchantOrderDispatch.query.filter(order_id=order_id).first() + if not disp: + return None + if disp.dispatch_actor_type == ACTOR_MERCHANT: + return { + 'dispatch_staff_type': ACTOR_MERCHANT, + 'dispatch_staff_uid': disp.dispatch_actor_id or '', + 'dispatch_staff_name': '商家老板', + 'dispatch_role_code': '', + 'dispatch_role_name': '商家老板', + 'dispatch_member_id': None, + } + if disp.staff_member_id: + m = MerchantStaffMember.query.filter(id=disp.staff_member_id).select_related('role').first() + if m: + return { + 'dispatch_staff_type': ACTOR_STAFF, + 'dispatch_staff_uid': m.staff_user_id, + 'dispatch_staff_name': m.display_name or (m.role.role_name if m.role else m.staff_user_id), + 'dispatch_role_code': m.role.role_code if m.role else '', + 'dispatch_role_name': m.role.role_name if m.role else '', + 'dispatch_member_id': m.id, + } + return { + 'dispatch_staff_type': disp.dispatch_actor_type, + 'dispatch_staff_uid': disp.dispatch_actor_id or '', + 'dispatch_staff_name': disp.dispatch_actor_id or '', + 'dispatch_role_code': '', + 'dispatch_role_name': '', + 'dispatch_member_id': disp.staff_member_id, + } + + +def enrich_order_detail_data(data, order_id): + """订单详情追加派单客服;打手头像优先用户表相对路径。""" + if not data or not isinstance(data, dict): + return data + payload = get_dispatch_staff_payload(order_id) + if payload: + data['dispatch_staff'] = payload + else: + data['dispatch_staff'] = None + dashou_uid = data.get('dashou_yonghuid') or data.get('fuwudashou_id') or '' + av = get_user_avatar_by_uid(dashou_uid) + if av: + data['dashou_avatar'] = av + return data + + +def staff_order_list_item(ext): + """子客服订单列表项:不含派单客服字段,打手头像走用户表。""" + from merchant_ops.services.order_query import staff_order_to_dict + d = staff_order_to_dict(ext) + pid = d.get('jiedan_dashou_id') + if pid: + d['jiedan_dashou_avatar'] = get_user_avatar_by_uid(pid) + return d diff --git a/merchant_ops/views_manage.py b/merchant_ops/views_manage.py index 127035b..0d21d1c 100644 --- a/merchant_ops/views_manage.py +++ b/merchant_ops/views_manage.py @@ -126,30 +126,49 @@ class StaffMemberListView(APIView): def post(self, request): try: + from datetime import date + from users.business_models import User + from merchant_ops.services.order_enrich import user_avatar_relative + mid = request.user.UserUID ensure_owner_merchant(mid, request.user) + today = date.today() members = MerchantStaffMember.query.filter( - merchant_id=mid, status=MEMBER_STATUS_ACTIVE, + merchant_id=mid, + status__in=[MEMBER_STATUS_ACTIVE, MEMBER_STATUS_DISABLED], ).select_related('role') result = [] for m in members: - stats = MerchantStaffDailyStats.query.filter(member_id=m.id).aggregate( + total_stats = MerchantStaffDailyStats.query.filter(member_id=m.id).aggregate( dispatch_count=Sum('dispatch_count'), settle_count=Sum('settle_count'), settle_amount=Sum('settle_amount'), + refund_count=Sum('refund_count'), ) - wallet = m.wallets.first() + today_stat = MerchantStaffDailyStats.query.filter( + member_id=m.id, stat_date=today, + ).first() + wallet = get_or_create_wallet(m) + u = User.query.filter(UserUID=m.staff_user_id).first() result.append({ 'id': m.id, 'uid': m.staff_user_id, 'nickname': m.display_name or m.staff_user_id, - 'isChief': m.role.role_code == 'CHIEF', - 'isFinance': m.role.role_code == 'FINANCE', - 'role_name': m.role.role_name, - 'orderCount': stats['dispatch_count'] or 0, - 'settleCount': stats['settle_count'] or 0, - 'settleAmount': str(stats['settle_amount'] or '0.00'), - 'quota_available': str(wallet.quota_available if wallet else 0), + 'avatar': user_avatar_relative(u), + 'role_name': m.role.role_name if m.role else '', + 'isChief': m.role.role_code == 'CHIEF' if m.role else False, + 'isFinance': m.role.role_code == 'FINANCE' if m.role else False, + 'status': m.status, + 'isDisabled': m.status == MEMBER_STATUS_DISABLED, + 'todayDispatchCount': today_stat.dispatch_count if today_stat else int(m.today_dispatch_count or 0), + 'dispatchCount': total_stats['dispatch_count'] or 0, + 'orderCount': total_stats['dispatch_count'] or 0, + 'settleCount': total_stats['settle_count'] or 0, + 'refundCount': total_stats['refund_count'] or 0, + 'settleAmount': str(total_stats['settle_amount'] or '0.00'), + 'quota_available': str(wallet.quota_available), + 'quota_total': str(wallet.quota_total), + 'quota_used': str(wallet.quota_used), }) return Response({'code': 0, 'msg': '成功', 'data': {'list': result}}) except Exception as e: diff --git a/merchant_ops/views_orders.py b/merchant_ops/views_orders.py index f806103..6a9029a 100644 --- a/merchant_ops/views_orders.py +++ b/merchant_ops/views_orders.py @@ -13,8 +13,8 @@ from merchant_ops.services.order_query import ( staff_apply_order_filters, staff_can_view_all_orders, staff_order_ext_qs, - staff_order_to_dict, ) +from merchant_ops.services.order_enrich import staff_order_list_item from merchant_ops.services.audit import audit_staff from merchant_ops.services.dispatch import staff_dispatch_order from merchant_ops.services.stats import bump_cancel_count, bump_penalty_count, update_merchant_and_staff_stats @@ -77,7 +77,7 @@ class StaffOrderListView(APIView): start = (page - 1) * page_size page_qs = base_qs.order_by('-Order__CreateTime')[start:start + page_size] - order_list = [staff_order_to_dict(ext) for ext in page_qs] + order_list = [staff_order_list_item(ext) for ext in page_qs] return Response({ 'code': 0, @@ -105,6 +105,9 @@ class StaffOrderDetailView(APIView): resp = proxy_merchant_order_view( request, member, ShangjiaDingdanXiangqingView, 'order_detail', ) + if resp.status_code == 200 and resp.data.get('code') == 0 and resp.data.get('data'): + from merchant_ops.services.order_enrich import enrich_order_detail_data + enrich_order_detail_data(resp.data['data'], pick_order_id(request.data)) return resp except Exception as e: return _err(e) @@ -186,6 +189,11 @@ class StaffRefundView(APIView): resp = proxy_merchant_order_view(request, member, ShangjiaTuikuanShenqingView, 'order_refund_apply') if resp.data.get('code') in (0, 200): audit_staff(member, 'REFUND_APPLY', request, resource_id=pick_order_id(request.data)) + from orders.models import Order + oid = pick_order_id(request.data) + o = Order.query.filter(OrderID=oid).first() + if o: + update_merchant_and_staff_stats(member.merchant_id, member, o.Amount, STAT_ACTION_REFUND) return resp except Exception as e: return _err(e) diff --git a/orders/views.py b/orders/views.py index 81ad512..715b0c9 100644 --- a/orders/views.py +++ b/orders/views.py @@ -2310,6 +2310,12 @@ class ShangjiaDingdanXiangqingView(APIView): 'xin_dingdan_id': xin_dingdan_id, } + try: + from merchant_ops.services.order_enrich import enrich_order_detail_data + enrich_order_detail_data(response_data, dingdan_id) + except Exception as e: + logger.warning(f'派单客服信息附加失败: {e}') + return Response({ 'code': 0, 'msg': '成功',