Commit 36c441051261011ade8d807982c1a22211bea1f8

Authored by YunaiV
1 parent 2fd201bf

✨ feat(im): 管理后台新增通话记录只读查询(列表 / 详情 / 参与者);im_rtc_participant 增加 call_id 关联 im_rtc_call.id

✨ feat(im): 管理后台新增通话记录页面(列表 + 详情抽屉 + 参与者表),消息预览补 RTC_CALL_START / END 文案
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/ImRtcCallManagerController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.controller.admin.manager.rtc;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  7 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerPageReqVO;
  9 +import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerRespVO;
  10 +import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcParticipantManagerRespVO;
  11 +import cn.iocoder.yudao.module.im.dal.dataobject.group.ImGroupDO;
  12 +import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
  13 +import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcParticipantDO;
  14 +import cn.iocoder.yudao.module.im.service.group.ImGroupService;
  15 +import cn.iocoder.yudao.module.im.service.rtc.ImRtcCallService;
  16 +import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
  17 +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
  18 +import io.swagger.v3.oas.annotations.Operation;
  19 +import io.swagger.v3.oas.annotations.Parameter;
  20 +import io.swagger.v3.oas.annotations.tags.Tag;
  21 +import jakarta.annotation.Resource;
  22 +import jakarta.validation.Valid;
  23 +import org.springframework.security.access.prepost.PreAuthorize;
  24 +import org.springframework.validation.annotation.Validated;
  25 +import org.springframework.web.bind.annotation.GetMapping;
  26 +import org.springframework.web.bind.annotation.RequestMapping;
  27 +import org.springframework.web.bind.annotation.RequestParam;
  28 +import org.springframework.web.bind.annotation.RestController;
  29 +
  30 +import java.util.Collections;
  31 +import java.util.List;
  32 +import java.util.Map;
  33 +
  34 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  36 +
  37 +@Tag(name = "管理后台 - IM 通话记录")
  38 +@RestController
  39 +@RequestMapping("/im/manager/rtc")
  40 +@Validated
  41 +public class ImRtcCallManagerController {
  42 +
  43 + @Resource
  44 + private ImRtcCallService rtcCallService;
  45 + @Resource
  46 + private ImGroupService groupService;
  47 +
  48 + @Resource
  49 + private AdminUserApi adminUserApi;
  50 +
  51 + @GetMapping("/page")
  52 + @Operation(summary = "获得通话记录分页")
  53 + @PreAuthorize("@ss.hasPermission('im:manager:rtc:query')")
  54 + public CommonResult<PageResult<ImRtcCallManagerRespVO>> getCallPage(@Valid ImRtcCallManagerPageReqVO pageReqVO) {
  55 + PageResult<ImRtcCallDO> pageResult = rtcCallService.getCallPage(pageReqVO);
  56 + return success(buildCallRespVOPage(pageResult));
  57 + }
  58 +
  59 + @GetMapping("/get")
  60 + @Operation(summary = "获得通话记录详情")
  61 + @Parameter(name = "id", description = "通话编号", required = true, example = "1024")
  62 + @PreAuthorize("@ss.hasPermission('im:manager:rtc:query')")
  63 + public CommonResult<ImRtcCallManagerRespVO> getCall(@RequestParam("id") Long id) {
  64 + ImRtcCallDO call = rtcCallService.getCall(id);
  65 + if (call == null) {
  66 + return success(null);
  67 + }
  68 + return success(CollUtil.getFirst(buildCallRespVOList(Collections.singletonList(call))));
  69 + }
  70 +
  71 + @GetMapping("/participant-list")
  72 + @Operation(summary = "获得通话参与者列表")
  73 + @Parameter(name = "id", description = "通话编号", required = true, example = "1024")
  74 + @PreAuthorize("@ss.hasPermission('im:manager:rtc:query')")
  75 + public CommonResult<List<ImRtcParticipantManagerRespVO>> getCallParticipantList(@RequestParam("id") Long id) {
  76 + List<ImRtcParticipantDO> participants = rtcCallService.getCallParticipantListByCallId(id);
  77 + if (CollUtil.isEmpty(participants)) {
  78 + return success(Collections.emptyList());
  79 + }
  80 + // 查询用户信息
  81 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
  82 + convertSet(participants, ImRtcParticipantDO::getUserId));
  83 + // 组装返回
  84 + return success(BeanUtils.toBean(participants, ImRtcParticipantManagerRespVO.class, vo ->
  85 + MapUtils.findAndThen(userMap, vo.getUserId(),
  86 + user -> vo.setUserNickname(user.getNickname()))));
  87 + }
  88 +
  89 + // ========== 私有方法:VO 组装 ==========
  90 +
  91 + private PageResult<ImRtcCallManagerRespVO> buildCallRespVOPage(PageResult<ImRtcCallDO> pageResult) {
  92 + if (CollUtil.isEmpty(pageResult.getList())) {
  93 + return PageResult.empty(pageResult.getTotal());
  94 + }
  95 + return new PageResult<>(buildCallRespVOList(pageResult.getList()), pageResult.getTotal());
  96 + }
  97 +
  98 + private List<ImRtcCallManagerRespVO> buildCallRespVOList(List<ImRtcCallDO> calls) {
  99 + // 查询用户信息
  100 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
  101 + convertSet(calls, ImRtcCallDO::getInviterUserId));
  102 + Map<Long, ImGroupDO> groupMap = groupService.getGroupMap(
  103 + convertSet(calls, ImRtcCallDO::getGroupId));
  104 + // 组装返回
  105 + return BeanUtils.toBean(calls, ImRtcCallManagerRespVO.class, vo -> {
  106 + MapUtils.findAndThen(userMap, vo.getInviterUserId(),
  107 + user -> vo.setInviterNickname(user.getNickname()));
  108 + MapUtils.findAndThen(groupMap, vo.getGroupId(),
  109 + group -> vo.setGroupName(group.getName()));
  110 + });
  111 + }
  112 +
  113 +}
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +
  9 +import java.time.LocalDateTime;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  12 +
  13 +@Schema(description = "管理后台 - IM 通话记录分页 Request VO")
  14 +@Data
  15 +@EqualsAndHashCode(callSuper = true)
  16 +public class ImRtcCallManagerPageReqVO extends PageParam {
  17 +
  18 + @Schema(description = "发起人用户编号", example = "1024")
  19 + private Long inviterUserId;
  20 +
  21 + @Schema(description = "会话类型", example = "1")
  22 + private Integer conversationType; // 参见 ImConversationTypeEnum 枚举类
  23 +
  24 + @Schema(description = "媒体类型", example = "1")
  25 + private Integer mediaType; // 参见 ImRtcCallMediaTypeEnum 枚举类
  26 +
  27 + @Schema(description = "通话状态", example = "10")
  28 + private Integer status; // 参见 ImRtcCallStatusEnum 枚举类
  29 +
  30 + @Schema(description = "结束原因", example = "1")
  31 + private Integer endReason; // 参见 ImRtcCallEndReasonEnum 枚举类
  32 +
  33 + @Schema(description = "发起时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]")
  34 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  35 + private LocalDateTime[] startTime;
  36 +
  37 +}
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcCallManagerRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "管理后台 - IM 通话记录 Response VO")
  9 +@Data
  10 +public class ImRtcCallManagerRespVO {
  11 +
  12 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  13 + private Long id;
  14 +
  15 + @Schema(description = "业务通话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "uuid-xxx")
  16 + private String room;
  17 +
  18 + @Schema(description = "会话类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Integer conversationType; // 参见 ImConversationTypeEnum 枚举类
  20 +
  21 + @Schema(description = "媒体类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  22 + private Integer mediaType; // 参见 ImRtcCallMediaTypeEnum 枚举类
  23 +
  24 + @Schema(description = "发起人用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  25 + private Long inviterUserId;
  26 +
  27 + @Schema(description = "发起人昵称", example = "张三")
  28 + private String inviterNickname;
  29 +
  30 + @Schema(description = "群编号;私聊为空", example = "999")
  31 + private Long groupId;
  32 +
  33 + @Schema(description = "群名称;私聊为空", example = "测试群")
  34 + private String groupName;
  35 +
  36 + @Schema(description = "通话状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  37 + private Integer status; // 参见 ImRtcCallStatusEnum 枚举类
  38 +
  39 + @Schema(description = "结束原因", example = "1")
  40 + private Integer endReason; // 参见 ImRtcCallEndReasonEnum 枚举类
  41 +
  42 + @Schema(description = "发起时间", requiredMode = Schema.RequiredMode.REQUIRED)
  43 + private LocalDateTime startTime;
  44 +
  45 + @Schema(description = "接通时间;未接通为空")
  46 + private LocalDateTime acceptTime;
  47 +
  48 + @Schema(description = "结束时间;未结束为空")
  49 + private LocalDateTime endTime;
  50 +
  51 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  52 + private LocalDateTime createTime;
  53 +
  54 +}
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/rtc/vo/ImRtcParticipantManagerRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "管理后台 - IM 通话参与者 Response VO")
  9 +@Data
  10 +public class ImRtcParticipantManagerRespVO {
  11 +
  12 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  13 + private Long id;
  14 +
  15 + @Schema(description = "通话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  16 + private Long callId;
  17 +
  18 + @Schema(description = "参与者用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  19 + private Long userId;
  20 +
  21 + @Schema(description = "参与者昵称", example = "张三")
  22 + private String userNickname;
  23 +
  24 + @Schema(description = "参与角色", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  25 + private Integer role; // 参见 ImRtcParticipantRoleEnum 枚举类
  26 +
  27 + @Schema(description = "参与状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
  28 + private Integer status; // 参见 ImRtcParticipantStatusEnum 枚举类
  29 +
  30 + @Schema(description = "被邀请时间", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + private LocalDateTime inviteTime;
  32 +
  33 + @Schema(description = "接听时间;未接听为空")
  34 + private LocalDateTime acceptTime;
  35 +
  36 + @Schema(description = "离开时间;未加入为空")
  37 + private LocalDateTime leaveTime;
  38 +
  39 +}
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcParticipantDO.java
@@ -35,6 +35,12 @@ public class ImRtcParticipantDO extends BaseDO { @@ -35,6 +35,12 @@ public class ImRtcParticipantDO extends BaseDO {
35 @TableId 35 @TableId
36 private Long id; 36 private Long id;
37 /** 37 /**
  38 + * 通话编号
  39 + * <p>
  40 + * 关联 {@link ImRtcCallDO#getId()}
  41 + */
  42 + private Long callId;
  43 + /**
38 * 业务通话编号 44 * 业务通话编号
39 * <p> 45 * <p>
40 * 关联 {@link ImRtcCallDO#getRoom()} 46 * 关联 {@link ImRtcCallDO#getRoom()}
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcCallMapper.java
1 package cn.iocoder.yudao.module.im.dal.mysql.rtc; 1 package cn.iocoder.yudao.module.im.dal.mysql.rtc;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
4 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerPageReqVO;
5 import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO; 7 import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
6 import com.baomidou.mybatisplus.core.toolkit.Wrappers; 8 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
7 import org.apache.ibatis.annotations.Mapper; 9 import org.apache.ibatis.annotations.Mapper;
@@ -48,4 +50,15 @@ public interface ImRtcCallMapper extends BaseMapperX&lt;ImRtcCallDO&gt; { @@ -48,4 +50,15 @@ public interface ImRtcCallMapper extends BaseMapperX&lt;ImRtcCallDO&gt; {
48 .lt(ImRtcCallDO::getStartTime, startTimeBefore)); 50 .lt(ImRtcCallDO::getStartTime, startTimeBefore));
49 } 51 }
50 52
  53 + default PageResult<ImRtcCallDO> selectPage(ImRtcCallManagerPageReqVO reqVO) {
  54 + return selectPage(reqVO, new LambdaQueryWrapperX<ImRtcCallDO>()
  55 + .eqIfPresent(ImRtcCallDO::getInviterUserId, reqVO.getInviterUserId())
  56 + .eqIfPresent(ImRtcCallDO::getConversationType, reqVO.getConversationType())
  57 + .eqIfPresent(ImRtcCallDO::getMediaType, reqVO.getMediaType())
  58 + .eqIfPresent(ImRtcCallDO::getStatus, reqVO.getStatus())
  59 + .eqIfPresent(ImRtcCallDO::getEndReason, reqVO.getEndReason())
  60 + .betweenIfPresent(ImRtcCallDO::getStartTime, reqVO.getStartTime())
  61 + .orderByDesc(ImRtcCallDO::getId));
  62 + }
  63 +
51 } 64 }
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcParticipantMapper.java
@@ -28,6 +28,10 @@ public interface ImRtcParticipantMapper extends BaseMapperX&lt;ImRtcParticipantDO&gt; @@ -28,6 +28,10 @@ public interface ImRtcParticipantMapper extends BaseMapperX&lt;ImRtcParticipantDO&gt;
28 return selectList(ImRtcParticipantDO::getRoom, room); 28 return selectList(ImRtcParticipantDO::getRoom, room);
29 } 29 }
30 30
  31 + default List<ImRtcParticipantDO> selectListByCallId(Long callId) {
  32 + return selectList(ImRtcParticipantDO::getCallId, callId);
  33 + }
  34 +
31 default List<ImRtcParticipantDO> selectListByStatusAndInviteTimeBefore(Integer status, LocalDateTime threshold) { 35 default List<ImRtcParticipantDO> selectListByStatusAndInviteTimeBefore(Integer status, LocalDateTime threshold) {
32 return selectList(new LambdaQueryWrapperX<ImRtcParticipantDO>() 36 return selectList(new LambdaQueryWrapperX<ImRtcParticipantDO>()
33 .eq(ImRtcParticipantDO::getStatus, status) 37 .eq(ImRtcParticipantDO::getStatus, status)
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallService.java
1 package cn.iocoder.yudao.module.im.service.rtc; 1 package cn.iocoder.yudao.module.im.service.rtc;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerPageReqVO;
3 import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallCreateReqVO; 5 import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallCreateReqVO;
4 import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallInviteReqVO; 6 import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallInviteReqVO;
5 import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO; 7 import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
@@ -138,4 +140,30 @@ public interface ImRtcCallService { @@ -138,4 +140,30 @@ public interface ImRtcCallService {
138 */ 140 */
139 void noAnswerCallCheck(Long userId, String room); 141 void noAnswerCallCheck(Long userId, String room);
140 142
  143 + // ==================== 管理后台 ====================
  144 +
  145 + /**
  146 + * 【管理后台】获得通话记录分页
  147 + *
  148 + * @param reqVO 分页查询条件
  149 + * @return 通话记录分页
  150 + */
  151 + PageResult<ImRtcCallDO> getCallPage(ImRtcCallManagerPageReqVO reqVO);
  152 +
  153 + /**
  154 + * 【管理后台】获得通话记录
  155 + *
  156 + * @param id 通话编号
  157 + * @return 通话记录
  158 + */
  159 + ImRtcCallDO getCall(Long id);
  160 +
  161 + /**
  162 + * 【管理后台】按通话编号查询参与者明细
  163 + *
  164 + * @param id 通话编号
  165 + * @return 参与者明细列表;通话不存在时返回空集合
  166 + */
  167 + List<ImRtcParticipantDO> getCallParticipantListByCallId(Long id);
  168 +
141 } 169 }
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImpl.java
@@ -4,7 +4,9 @@ import cn.hutool.core.collection.CollUtil; @@ -4,7 +4,9 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.IdUtil; 4 import cn.hutool.core.util.IdUtil;
5 import cn.hutool.core.util.ObjUtil; 5 import cn.hutool.core.util.ObjUtil;
6 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 8 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  9 +import cn.iocoder.yudao.module.im.controller.admin.manager.rtc.vo.ImRtcCallManagerPageReqVO;
8 import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallCreateReqVO; 10 import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallCreateReqVO;
9 import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallInviteReqVO; 11 import cn.iocoder.yudao.module.im.controller.admin.rtc.vo.ImRtcCallInviteReqVO;
10 import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO; 12 import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
@@ -215,13 +217,13 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { @@ -215,13 +217,13 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
215 rtcCallMapper.insert(call); 217 rtcCallMapper.insert(call);
216 // 2.2 批量 INSERT 参与表:发起人即时 JOINED,被邀请人 INVITING 等接通 218 // 2.2 批量 INSERT 参与表:发起人即时 JOINED,被邀请人 INVITING 等接通
217 List<ImRtcParticipantDO> participants = new ArrayList<>(invitees.size() + 1); 219 List<ImRtcParticipantDO> participants = new ArrayList<>(invitees.size() + 1);
218 - participants.add(new ImRtcParticipantDO().setRoom(room).setUserId(inviterId) 220 + participants.add(new ImRtcParticipantDO().setCallId(call.getId()).setRoom(room).setUserId(inviterId)
219 .setRole(ImRtcParticipantRoleEnum.INVITER.getRole()) 221 .setRole(ImRtcParticipantRoleEnum.INVITER.getRole())
220 .setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus()) 222 .setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus())
221 .setInviteTime(now).setAcceptTime(now)); 223 .setInviteTime(now).setAcceptTime(now));
222 for (Long inviteeId : invitees) { 224 for (Long inviteeId : invitees) {
223 participants.add(new ImRtcParticipantDO() 225 participants.add(new ImRtcParticipantDO()
224 - .setRoom(room).setUserId(inviteeId) 226 + .setCallId(call.getId()).setRoom(room).setUserId(inviteeId)
225 .setRole(ImRtcParticipantRoleEnum.INVITEE.getRole()) 227 .setRole(ImRtcParticipantRoleEnum.INVITEE.getRole())
226 .setStatus(ImRtcParticipantStatusEnum.INVITING.getStatus()) 228 .setStatus(ImRtcParticipantStatusEnum.INVITING.getStatus())
227 .setInviteTime(now)); 229 .setInviteTime(now));
@@ -260,7 +262,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { @@ -260,7 +262,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
260 } 262 }
261 } else { 263 } else {
262 // 旁观者主动加入:INSERT role=ACTIVE_JOIN 264 // 旁观者主动加入:INSERT role=ACTIVE_JOIN
263 - rtcParticipantMapper.insert(new ImRtcParticipantDO().setRoom(call.getRoom()) 265 + rtcParticipantMapper.insert(new ImRtcParticipantDO()
  266 + .setCallId(call.getId()).setRoom(call.getRoom())
264 .setUserId(userId).setRole(ImRtcParticipantRoleEnum.ACTIVE_JOIN.getRole()) 267 .setUserId(userId).setRole(ImRtcParticipantRoleEnum.ACTIVE_JOIN.getRole())
265 .setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus()).setInviteTime(now).setAcceptTime(now)); 268 .setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus()).setInviteTime(now).setAcceptTime(now));
266 } 269 }
@@ -292,7 +295,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { @@ -292,7 +295,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
292 // 2. 批量 INSERT 新邀请人 295 // 2. 批量 INSERT 新邀请人
293 LocalDateTime now = LocalDateTime.now(); 296 LocalDateTime now = LocalDateTime.now();
294 List<ImRtcParticipantDO> participants = CollectionUtils.convertList(incomingUserIds, inviteeId -> 297 List<ImRtcParticipantDO> participants = CollectionUtils.convertList(incomingUserIds, inviteeId ->
295 - new ImRtcParticipantDO().setRoom(call.getRoom()).setUserId(inviteeId) 298 + new ImRtcParticipantDO().setCallId(call.getId()).setRoom(call.getRoom()).setUserId(inviteeId)
296 .setRole(ImRtcParticipantRoleEnum.INVITEE.getRole()) 299 .setRole(ImRtcParticipantRoleEnum.INVITEE.getRole())
297 .setStatus(ImRtcParticipantStatusEnum.INVITING.getStatus()).setInviteTime(now)); 300 .setStatus(ImRtcParticipantStatusEnum.INVITING.getStatus()).setInviteTime(now));
298 rtcParticipantMapper.insertBatch(participants); 301 rtcParticipantMapper.insertBatch(participants);
@@ -1071,4 +1074,21 @@ public class ImRtcCallServiceImpl implements ImRtcCallService { @@ -1071,4 +1074,21 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
1071 user == null ? null : user.getNickname(), String.valueOf(userId)); 1074 user == null ? null : user.getNickname(), String.valueOf(userId));
1072 } 1075 }
1073 1076
  1077 + // ==================== 管理后台 ====================
  1078 +
  1079 + @Override
  1080 + public PageResult<ImRtcCallDO> getCallPage(ImRtcCallManagerPageReqVO reqVO) {
  1081 + return rtcCallMapper.selectPage(reqVO);
  1082 + }
  1083 +
  1084 + @Override
  1085 + public ImRtcCallDO getCall(Long id) {
  1086 + return rtcCallMapper.selectById(id);
  1087 + }
  1088 +
  1089 + @Override
  1090 + public List<ImRtcParticipantDO> getCallParticipantListByCallId(Long id) {
  1091 + return rtcParticipantMapper.selectListByCallId(id);
  1092 + }
  1093 +
1074 } 1094 }
yudao-module-im/src/test/resources/sql/create_tables.sql
@@ -202,6 +202,7 @@ CREATE TABLE IF NOT EXISTS &quot;im_rtc_call&quot; ( @@ -202,6 +202,7 @@ CREATE TABLE IF NOT EXISTS &quot;im_rtc_call&quot; (
202 202
203 CREATE TABLE IF NOT EXISTS "im_rtc_participant" ( 203 CREATE TABLE IF NOT EXISTS "im_rtc_participant" (
204 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号', 204 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号',
  205 + "call_id" bigint NOT NULL COMMENT '通话编号',
205 "room" varchar(64) NOT NULL COMMENT '业务通话编号', 206 "room" varchar(64) NOT NULL COMMENT '业务通话编号',
206 "user_id" bigint NOT NULL COMMENT '参与者用户编号', 207 "user_id" bigint NOT NULL COMMENT '参与者用户编号',
207 "role" tinyint NOT NULL COMMENT '参与角色', 208 "role" tinyint NOT NULL COMMENT '参与角色',