diff --git a/backend/go-service/app/meeting/service/meeting_service.go b/backend/go-service/app/meeting/service/meeting_service.go index d7e787f..eb27856 100644 --- a/backend/go-service/app/meeting/service/meeting_service.go +++ b/backend/go-service/app/meeting/service/meeting_service.go @@ -675,8 +675,22 @@ func (s *MeetingService) JoinRoom(ctx context.Context, userID int64, code, passw return room, participant, routerID, nil } +// isCloudLawRoom 判断是否为云律视频咨询房间:host 为云律自动创建的用户(邮箱后缀 @cloud-law.local)。 +// 云律房间语义是「发起人(用户)↔接单人(律师)」一对一咨询,发起人挂断即咨询结束。 +func (s *MeetingService) isCloudLawRoom(ctx context.Context, hostID int64) bool { + if s.userResolver == nil || hostID <= 0 { + return false + } + users, err := s.userResolver.GetUsersByIDs(ctx, []int64{hostID}) + if err != nil || len(users) == 0 { + return false + } + return strings.HasSuffix(users[0].Email, "@cloud-law.local") +} + // LeaveRoom 用户主动离会 // 若离开者为 host 且房间内还有其他活跃成员:事务内转让给最早加入者;若为空房:关闭房间(status=Ended, reason=empty_ttl) +// 云律房间例外:发起人(host)离会即结束整场会议(见下方说明) func (s *MeetingService) LeaveRoom(ctx context.Context, userID int64, code string) (int, error) { funcName := "service.meeting_service.LeaveRoom" @@ -712,6 +726,16 @@ func (s *MeetingService) LeaveRoom(ctx context.Context, userID int64, code strin } if participant.Role == constants.MeetingRoleHost && len(actives) > 0 { + // 云律视频咨询:发起人(host)即咨询者,挂断/离会即代表咨询结束, + // 应直接结束整场会议,而不是把主持人转让给律师让会议继续 + //(否则表现为「用户已挂断、律师端会议仍在、云律 status 一直 accepted」)。 + if s.isCloudLawRoom(ctx, room.HostID) { + if endErr := s.EndRoomForInternal(ctx, code); endErr != nil { + logs.Warn(ctx, funcName, "云律发起人离会自动结束会议失败", + zap.String("room_code", code), zap.Int64("host_id", room.HostID), zap.Error(endErr)) + } + return duration, nil + } newHost := actives[0] // P1-1:TransferHost 内部事务已同时更新 meeting_rooms.host_id,不再需要单独 UpdateHost if txErr := s.participantDAO.TransferHost(ctx, room.ID, userID, newHost.UserID); txErr != nil {