抢单建群写入双方头像昵称元数据,更换打手后补建群聊
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user