fix: 组队群统一 group_订单ID,入队发消息并拉商家/老板

开组/入队订阅派单方;发送「已组队」;进聊与代理发消息在有组队时走订单群;队友可进群。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-27 07:59:16 +08:00
parent 96f1a80395
commit caef4bf56c
3 changed files with 149 additions and 9 deletions

View File

@@ -124,6 +124,99 @@ def _subscribe_uids_to_order_group(order_id: str, uids: list):
return False
def _dashou_display_name(uid: str) -> str:
try:
from users.business_models import User
from users.models import UserDashou
u = User.query.filter(UserUID=uid).first()
if not u:
return f'打手{(uid or "")[:6]}'
try:
p = u.DashouProfile
if p and p.nicheng:
return p.nicheng
except Exception:
pass
try:
p = UserDashou.query.filter(user=u).first()
if p and p.nicheng:
return p.nicheng
except Exception:
pass
return f'打手{(uid or "")[:6]}'
except Exception:
return f'打手{(uid or "")[:6]}'
def _sync_team_order_group_chat(order, dashou_uids: list, *, announce_uid=None, announce_text=None):
"""
组队群统一 group_{订单ID}
- 订阅:打手们 + 商家/老板(派单方)
- 可选:发送入队/开组系统消息,触发监听中用户实时收到
"""
oid = (getattr(order, 'OrderID', None) or '').strip()
if not oid:
return False
try:
from utils.chat_utils import (
_subscribe_users_to_group,
_send_group_message,
_get_self_goeasy_appkey,
_get_self_goeasy_secret,
_get_local_partner_info,
_full_local_avatar,
)
appkey = _get_self_goeasy_appkey()
secret = _get_self_goeasy_secret()
if not appkey:
return False
group_id = f'group_{oid}'
user_ids = []
for u in dashou_uids or []:
u = (u or '').strip()
if u:
gid = f'Ds{u}'
if gid not in user_ids:
user_ids.append(gid)
partner_id, partner_name, partner_avatar = _get_local_partner_info(order)
if partner_id and partner_id not in user_ids:
user_ids.append(partner_id)
if not user_ids:
return False
ok = _subscribe_users_to_group(user_ids, [group_id], appkey, secret)
if not ok:
logger.warning('组队订阅群失败 order=%s users=%s', oid, user_ids)
if announce_uid and announce_text:
sender_id = f'Ds{announce_uid}'
sender_name = _dashou_display_name(announce_uid)
sender_avatar = ''
try:
from users.business_models import User
uu = User.query.filter(UserUID=announce_uid).first()
if uu:
sender_avatar = _full_local_avatar(getattr(uu, 'Avatar', None) or '')
except Exception:
pass
desc = (order.Description or '')[:20]
group_name = (desc + '') if order.Description and len(order.Description) > 20 else (order.Description or f'订单{oid}')
sent = _send_group_message(
appkey, secret, group_id, sender_id, sender_name, sender_avatar,
announce_text, None, group_name=group_name, order_id=oid,
)
if not sent:
logger.warning('组队群消息发送失败 order=%s text=%s', oid, announce_text)
return bool(ok and sent)
return bool(ok)
except Exception as e:
logger.warning('组队群同步失败 order=%s: %s', oid, e)
return False
@transaction.atomic
def open_recruit(
*,
@@ -210,7 +303,13 @@ def open_recruit(
joined_at=now,
).save()
_subscribe_uids_to_order_group(oid, [leader_uid])
name = _dashou_display_name(leader_uid)
_sync_team_order_group_chat(
order,
[leader_uid],
announce_uid=leader_uid,
announce_text=f'{name} 已开启组队招募,请在组队群沟通',
)
_log(club_id, oid, rec.id, leader_uid, 'open', f'mode={mode} need={need} display={display}')
return rec
@@ -429,7 +528,13 @@ def join_recruit(*, recruit_id: int, user_uid: str, game_id: str, request=None,
TeamRecruit.objects.filter(id=rec.id).update(joined_count=F('joined_count') + 1, UpdateTime=now)
rec.refresh_from_db()
_set_dashou_busy(user_uid, True)
_subscribe_uids_to_order_group(rec.order_id, [user_uid, rec.leader_uid])
name = _dashou_display_name(user_uid)
_sync_team_order_group_chat(
order,
[user_uid, rec.leader_uid, order.PlayerID],
announce_uid=user_uid,
announce_text=f'{name} 已组队',
)
_log(rec.club_id, rec.order_id, rec.id, user_uid, 'join', game_id)
if int(rec.joined_count or 0) >= int(rec.need_count or 0):

View File

@@ -42,7 +42,7 @@ from utils.weixin_broadcast import WeixinBroadcastSender
from utils.money import yuan_to_fen
from utils.chat_utils import (
_send_group_message, _subscribe_users_to_group, establish_order_chat,
prepare_order_group_chat, resolve_pair_group_id,
prepare_order_group_chat, resolve_pair_group_id, resolve_order_chat_group_id,
parse_pair_from_group_id, resolve_pair_from_order, check_pair_chat_permission,
query_pair_orders, order_to_chat_dict,
)
@@ -205,7 +205,22 @@ def check_user_permission(identity_type, uid, order):
except UserDashou.DoesNotExist:
return False, '该用户不是打手'
if order.PlayerID != uid:
return False, '你不是该订单的接单打手'
# 组队队友也可进订单组队群
try:
from orders.models import TeamMember, TeamRecruit
in_team = TeamMember.query.filter(
order_id=order.OrderID,
user_uid=uid,
join_status=TeamMember.JOIN_ACTIVE,
).exists()
recruit_ok = TeamRecruit.query.filter(
order_id=order.OrderID,
status__in=[TeamRecruit.STATUS_RECRUITING, TeamRecruit.STATUS_LOCKED],
).exists()
if not (in_team and recruit_ok):
return False, '你不是该订单的接单打手'
except Exception:
return False, '你不是该订单的接单打手'
elif identity_type == 'shangjia':
try:
@@ -248,13 +263,16 @@ class DaiLiQunLiaoXiaoXiView(APIView):
def post(self, request):
# ===== 1. 参数解析 =====
order_id = request.data.get('orderId')
identity_type = request.data.get('identityType') # dashou / shangjia / boss
identity_type = request.data.get('identityType') # dashou / PlayerID / shangjia / boss
sender_name = request.data.get('senderName', '')
sender_avatar_raw = request.data.get('senderAvatar', '')
message_type = request.data.get('messageType', 'text')
message_text = request.data.get('text', '')
order_payload = request.data.get('orderPayload', None)
if identity_type == 'dashou':
identity_type = 'PlayerID'
logger.info(f"[群聊代理] 收到请求: orderId={order_id}, identityType={identity_type}, "
f"messageType={message_type}, text={message_text[:20]}...")
@@ -289,8 +307,8 @@ class DaiLiQunLiaoXiaoXiView(APIView):
logger.error("[群聊代理] 我方 GoEasy AppKey 未配置")
return Response({'code': 500, 'msg': '系统配置错误(APPKEY)'})
# ===== 6. 公共群信息(新单走配对群,与文赫一致) =====
real_group_id = resolve_pair_group_id(order) or f"group_{order.OrderID}"
# ===== 6. 有组队用 group_{订单},否则配对群 =====
real_group_id = resolve_order_chat_group_id(order) or f"group_{order.OrderID}"
group_name = (order.Description[:20] + '') if order.Description and len(order.Description) > 20 else f"订单{order.OrderID}"
sender_avatar = full_avatar(sender_avatar_raw) if sender_avatar_raw else full_avatar('')

View File

@@ -104,6 +104,23 @@ def resolve_pair_group_id(order):
return None
def resolve_order_chat_group_id(order):
"""
进订单聊天用的群 ID
- 存在进行中组队 → 统一 group_{订单ID}(组队成员 + 商家/老板同群)
- 否则 → 配对群
"""
oid = (getattr(order, 'OrderID', None) or '').strip()
if oid:
try:
from orders.services.team_recruit import get_active_recruit
if get_active_recruit(oid):
return f'group_{oid}'
except Exception as e:
logger.warning('resolve_order_chat_group_id 查组队失败 order=%s: %s', oid, e)
return resolve_pair_group_id(order) or (f'group_{oid}' if oid else None)
def parse_pair_from_group_id(group_id):
"""从配对群 ID 解析打手 uid、对方 uid、对方角色(shangjia/boss)"""
if not group_id:
@@ -202,8 +219,8 @@ def _get_dashou_profile(order):
def build_order_group_chat_payload(order, viewer_backend_identity, viewer_uid):
"""构建前端 ltdhzb 所需群聊元数据(新群用打手+商家/老板配对 groupId"""
group_id = resolve_pair_group_id(order) or f'group_{order.OrderID}'
"""构建前端 ltdhzb 所需群聊元数据(有组队时用 group_{订单ID}"""
group_id = resolve_order_chat_group_id(order) or f'group_{order.OrderID}'
order_desc = order.Description or ''
group_name = (
(order_desc[:20] + '') if order_desc and len(order_desc) > 20