抢单建群写入双方头像昵称元数据,更换打手后补建群聊

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-06-23 23:21:21 +08:00
parent 2db394b2f9
commit 56c66846cc
2 changed files with 180 additions and 35 deletions

View File

@@ -4424,6 +4424,7 @@ from peizhi.models import ClubConfig
from utils.chat_utils import (
_send_group_message, _subscribe_users_to_group,
resolve_group_id_for_order, prepare_order_group_chat,
build_pair_to_data_for_order,
)
logger = logging.getLogger('dingdan')
@@ -4495,7 +4496,8 @@ def subscribe_users_to_group(user_ids, group_ids, appkey=None, secret=None):
def send_group_message(
appkey, secret, group_id, sender_id, sender_name, sender_avatar,
message_text='', custom_payload=None, group_name='', order_id='', is_cross=0
message_text='', custom_payload=None, group_name='', order_id='', is_cross=0,
to_data_extra=None,
):
"""
通过 GoEasy REST API 发送群消息。
@@ -4503,12 +4505,20 @@ def send_group_message(
custom_payload: 自定义消息体(如订单卡片),此时 type 设为 'order'
"""
url = 'https://rest-hangzhou.goeasy.io/v2/im/message'
to_data = {
"name": group_name or group_id,
"avatar": sender_avatar or '',
"orderId": order_id,
"isCross": is_cross
}
sender_avatar = sender_avatar or ''
if to_data_extra:
to_data = dict(to_data_extra)
if order_id and 'orderId' not in to_data:
to_data['orderId'] = order_id
if 'isCross' not in to_data:
to_data['isCross'] = is_cross
else:
to_data = {
"name": group_name or group_id,
"avatar": sender_avatar,
"orderId": order_id,
"isCross": is_cross
}
msg_type = 'order' if custom_payload else 'text'
payload = custom_payload if custom_payload else message_text
@@ -4707,6 +4717,8 @@ class DaiLiQunLiaoXiaoXiView(APIView):
custom_payload = order_payload if message_type == 'order' else None
text_content = message_text
pair_to_data = build_pair_to_data_for_order(order, viewer_goeasy_id=sender_id)
# ---------- 先向我方群发送消息(永远执行) ----------
local_ok = send_group_message(
appkey=self_appkey,
@@ -4719,7 +4731,8 @@ class DaiLiQunLiaoXiaoXiView(APIView):
custom_payload=custom_payload,
group_name=group_name,
order_id=order.dingdan_id,
is_cross=is_cross
is_cross=is_cross,
to_data_extra=pair_to_data,
)
if not local_ok:
return Response({'code': 500, 'msg': '消息发送失败'})
@@ -6212,6 +6225,11 @@ class AdGengHuanDaShou(APIView):
dingdan_obj.zhuangtai = 2 # 进行中状态
dingdan_obj.save()
try:
establish_order_chat_with_retry(dingdan_obj.dingdan_id, max_rounds=3)
except Exception as chat_err:
logger.error(f"更换打手后建聊失败: {chat_err}", exc_info=True)
# 13. 返回成功响应
return Response({
'code': 0,

View File

@@ -148,10 +148,85 @@ def _subscribe_users_to_group(user_ids, group_ids, appkey=None, secret=None):
logger.error(f"订阅异常: {e}", exc_info=True)
return False
def _goeasy_to_yonghuid(goeasy_id):
if not goeasy_id:
return ''
if goeasy_id.startswith('Boss'):
return goeasy_id[4:]
if goeasy_id.startswith('Ds') or goeasy_id.startswith('Sj'):
return goeasy_id[2:]
return goeasy_id
def _ensure_avatar_url(avatar_url):
"""头像为空时返回俱乐部默认头像(完整 URL"""
return avatar_url or _full_local_avatar('')
def _build_pair_group_to_data(dashou_goeasy_id, dashou_name, dashou_avatar,
partner_goeasy_id, partner_name, partner_avatar,
order_id=None, order_desc=None, is_cross=0,
viewer_goeasy_id=None):
"""群会话 to.data同时写入打手/对方双方 ID、昵称、头像前端按当前身份取对方展示"""
dashou_avatar = _ensure_avatar_url(dashou_avatar)
partner_avatar = _ensure_avatar_url(partner_avatar)
dashou_uid = _goeasy_to_yonghuid(dashou_goeasy_id)
partner_uid = _goeasy_to_yonghuid(partner_goeasy_id)
dashou_name = dashou_name or f'打手{dashou_uid}'
partner_name = partner_name or f'用户{partner_uid}'
to_data = {
'dashouGoEasyId': dashou_goeasy_id,
'partnerGoEasyId': partner_goeasy_id,
'dashouYonghuid': dashou_uid,
'partnerYonghuid': partner_uid,
'dashouName': dashou_name,
'partnerName': partner_name,
'dashouAvatar': dashou_avatar,
'partnerAvatar': partner_avatar,
'isCross': is_cross,
}
if order_id:
to_data['orderId'] = order_id
if order_desc:
to_data['orderDesc'] = order_desc[:300]
if viewer_goeasy_id == dashou_goeasy_id:
to_data['name'] = partner_name
to_data['avatar'] = partner_avatar
elif viewer_goeasy_id == partner_goeasy_id:
to_data['name'] = dashou_name
to_data['avatar'] = dashou_avatar
else:
to_data['name'] = partner_name
to_data['avatar'] = partner_avatar
return to_data
def build_pair_to_data_for_order(order, viewer_goeasy_id=None):
dashou_uid = order.jiedan_dashou_id
if not dashou_uid:
return None
dashou_goeasy_id = f'Ds{dashou_uid}'
dashou_name, dashou_avatar = _resolve_goeasy_user_display(dashou_goeasy_id)
partner_goeasy_id, partner_name, partner_avatar = _get_local_partner_info(order)
if not partner_goeasy_id:
return None
order_desc = (order.jieshao or '').strip()
if order.beizhu:
order_desc = f"{order_desc} | 备注:{order.beizhu}" if order_desc else f"备注:{order.beizhu}"
return _build_pair_group_to_data(
dashou_goeasy_id, dashou_name, dashou_avatar,
partner_goeasy_id, partner_name, partner_avatar,
order_id=order.dingdan_id, order_desc=order_desc,
is_cross=order.is_cross or 0, viewer_goeasy_id=viewer_goeasy_id,
)
# ========== 发送群消息(完整参数) ==========
def _send_group_message(appkey, secret, group_id, sender_id, sender_name, sender_avatar,
message_text, custom_payload=None, group_name=None, order_id=None, is_cross=0,
list_avatar=None, order_desc=None):
list_avatar=None, order_desc=None, to_data_extra=None):
if not appkey:
appkey = _get_self_goeasy_appkey()
if not secret:
@@ -162,23 +237,32 @@ def _send_group_message(appkey, secret, group_id, sender_id, sender_name, sender
url = 'https://rest-hangzhou.goeasy.io/v2/im/message'
# to.data 包含群聊展示信息及业务字段
to_data = {
"name": group_name or group_id,
"avatar": list_avatar or sender_avatar or "",
}
if order_id:
to_data["orderId"] = order_id
if order_desc:
to_data["orderDesc"] = order_desc[:300]
to_data["isCross"] = is_cross
sender_avatar = _ensure_avatar_url(sender_avatar)
# to.data优先使用配对群完整元数据双方头像/昵称)
if to_data_extra:
to_data = dict(to_data_extra)
if order_id and 'orderId' not in to_data:
to_data['orderId'] = order_id
if order_desc and 'orderDesc' not in to_data:
to_data['orderDesc'] = order_desc[:300]
else:
to_data = {
"name": group_name or group_id,
"avatar": _ensure_avatar_url(list_avatar or sender_avatar),
}
if order_id:
to_data["orderId"] = order_id
if order_desc:
to_data["orderDesc"] = order_desc[:300]
to_data["isCross"] = is_cross
payload_str = custom_payload.get("text", message_text) if custom_payload else message_text
request_body = {
"appkey": appkey,
"senderId": sender_id,
"senderData": {"avatar": sender_avatar, "name": sender_name},
"senderData": {"avatar": sender_avatar, "name": sender_name or sender_id},
"to": {
"type": "group",
"id": group_id,
@@ -368,12 +452,12 @@ def establish_order_chat_with_retry(dingdan_id, max_rounds=3):
# ========== 普通订单 / 我方派单 ==========
def _push_order_card_message(appkey, secret, order, group_id, sender_id, sender_name, sender_avatar,
group_name, list_avatar, order_desc):
to_data_extra):
card_text = _build_order_card_text(order)
return _send_group_message(
appkey, secret, group_id, sender_id, sender_name, sender_avatar,
card_text, None, group_name=group_name, order_id=order.dingdan_id,
is_cross=order.is_cross or 0, list_avatar=list_avatar, order_desc=order_desc
card_text, None, order_id=order.dingdan_id,
is_cross=order.is_cross or 0, to_data_extra=to_data_extra,
)
@@ -423,6 +507,13 @@ def prepare_order_group_chat(dingdan_id, caller_goeasy_id, push_order_card=False
if order.beizhu:
order_desc = f"{order_desc} | 备注:{order.beizhu}" if order_desc else f"备注:{order.beizhu}"
display_group_name = counterpart_name or '聊天'
pair_to_data = _build_pair_group_to_data(
dashou_goeasy_id, dashou_name, dashou_avatar,
partner_goeasy_id, partner_name, partner_avatar,
order_id=order.dingdan_id, order_desc=order_desc,
is_cross=1 if order.is_cross == 1 else 0,
viewer_goeasy_id=caller_goeasy_id,
)
user_ids = list({dashou_goeasy_id, partner_goeasy_id, caller_goeasy_id})
subscribe_ok = _retry_call(
@@ -436,7 +527,7 @@ def prepare_order_group_chat(dingdan_id, caller_goeasy_id, push_order_card=False
card_ok = _retry_call(
_push_order_card_message, 3, 0.4,
appkey, secret, order, group_id, caller_goeasy_id, caller_name, caller_avatar,
display_group_name, counterpart_avatar, order_desc
pair_to_data,
)
_ensure_liaotian_record(group_id, partner_goeasy_id, dashou_goeasy_id)
@@ -445,10 +536,19 @@ def prepare_order_group_chat(dingdan_id, caller_goeasy_id, push_order_card=False
'groupId': group_id,
'orderId': order.dingdan_id,
'groupName': display_group_name,
'groupAvatar': counterpart_avatar or '',
'groupAvatar': counterpart_avatar or _full_local_avatar(''),
'counterpartId': counterpart_id,
'counterpartName': counterpart_name,
'counterpartAvatar': counterpart_avatar or '',
'counterpartAvatar': counterpart_avatar or _full_local_avatar(''),
'counterpartYonghuid': _goeasy_to_yonghuid(counterpart_id),
'dashouGoEasyId': dashou_goeasy_id,
'partnerGoEasyId': partner_goeasy_id,
'dashouYonghuid': dashou_uid,
'partnerYonghuid': _goeasy_to_yonghuid(partner_goeasy_id),
'dashouName': dashou_name,
'partnerName': partner_name,
'dashouAvatar': dashou_avatar or _full_local_avatar(''),
'partnerAvatar': partner_avatar or _full_local_avatar(''),
'orderDesc': order_desc,
'orderJine': str(order.jine),
'orderZhuangtai': order.zhuangtai,
@@ -467,21 +567,40 @@ def _handle_local_order(order, dashou_goeasy_id, dashou_name, dashou_avatar, app
order_desc = (order.jieshao or '').strip()
if order.beizhu:
order_desc = f"{order_desc} | 备注:{order.beizhu}" if order_desc else f"备注:{order.beizhu}"
if not partner_goeasy_id:
logger.error(f"订单 {order.dingdan_id} 无法获取下单方 GoEasy 标识")
subscribe_ok = _retry_call(
_subscribe_users_to_group, 5, 0.4,
[dashou_goeasy_id], [group_id], appkey, secret
)
fallback_to_data = {
'name': dashou_name,
'avatar': _ensure_avatar_url(dashou_avatar),
'dashouGoEasyId': dashou_goeasy_id,
'dashouYonghuid': dashou_uid,
'dashouName': dashou_name,
'dashouAvatar': _ensure_avatar_url(dashou_avatar),
'orderId': order.dingdan_id,
'orderDesc': order_desc,
'isCross': order.is_cross or 0,
}
msg_ok = _retry_call(
_send_group_message, 3, 0.4,
appkey, secret, group_id, dashou_goeasy_id, dashou_name, dashou_avatar,
"订单已接单,请等待对方上线。", None, group_name=group_name,
"订单已接单,请等待对方上线。", None,
order_id=order.dingdan_id, is_cross=order.is_cross,
list_avatar=partner_avatar, order_desc=order_desc
to_data_extra=fallback_to_data,
)
return subscribe_ok or msg_ok
pair_to_data = _build_pair_group_to_data(
dashou_goeasy_id, dashou_name, dashou_avatar,
partner_goeasy_id, partner_name, partner_avatar,
order_id=order.dingdan_id, order_desc=order_desc,
is_cross=order.is_cross or 0,
)
subscribe_ok = _retry_call(
_subscribe_users_to_group, 5, 0.4,
[dashou_goeasy_id, partner_goeasy_id], [group_id], appkey, secret
@@ -491,22 +610,22 @@ def _handle_local_order(order, dashou_goeasy_id, dashou_name, dashou_avatar, app
success1 = _retry_call(
_send_group_message, 3, 0.4,
appkey, secret, group_id, dashou_goeasy_id, dashou_name, dashou_avatar,
init_msg_text, None, group_name=group_name, order_id=order.dingdan_id,
is_cross=order.is_cross, list_avatar=partner_avatar, order_desc=order_desc
init_msg_text, None, order_id=order.dingdan_id,
is_cross=order.is_cross, to_data_extra=pair_to_data,
)
partner_msg = "订单已确认,请开始服务。"
success2 = _retry_call(
_send_group_message, 3, 0.4,
appkey, secret, group_id, partner_goeasy_id, partner_name, partner_avatar,
partner_msg, None, group_name=group_name, order_id=order.dingdan_id,
is_cross=order.is_cross, list_avatar=dashou_avatar, order_desc=order_desc
partner_msg, None, order_id=order.dingdan_id,
is_cross=order.is_cross, to_data_extra=pair_to_data,
)
card_ok = _retry_call(
_push_order_card_message, 3, 0.4,
appkey, secret, order, group_id, dashou_goeasy_id, dashou_name, dashou_avatar,
group_name, partner_avatar, order_desc
pair_to_data,
)
liaotian_ok = _ensure_liaotian_record(group_id, partner_goeasy_id, dashou_goeasy_id)
@@ -695,6 +814,14 @@ def _create_local_group_only(order, dashou_goeasy_id, dashou_name, dashou_avatar
order_desc = (order.jieshao or '').strip()
if order.beizhu:
order_desc = f"{order_desc} | 备注:{order.beizhu}" if order_desc else f"备注:{order.beizhu}"
to_data = None
if partner_goeasy_id:
to_data = _build_pair_group_to_data(
dashou_goeasy_id, dashou_name, dashou_avatar,
partner_goeasy_id, partner_name, partner_avatar,
order_id=order.dingdan_id, order_desc=order_desc,
is_cross=order.is_cross or 0,
)
subscribe_ok = _retry_call(
_subscribe_users_to_group, 5, 0.4,
[dashou_goeasy_id], [group_id], appkey, secret
@@ -702,7 +829,7 @@ def _create_local_group_only(order, dashou_goeasy_id, dashou_name, dashou_avatar
msg_ok = _retry_call(
_send_group_message, 3, 0.4,
appkey, secret, group_id, dashou_goeasy_id, dashou_name, dashou_avatar,
"订单已接单。", None, group_name=group_name, order_id=order.dingdan_id,
is_cross=order.is_cross, list_avatar=partner_avatar, order_desc=order_desc
"订单已接单。", None, order_id=order.dingdan_id,
is_cross=order.is_cross, to_data_extra=to_data,
)
return subscribe_ok or msg_ok