Commit 96f2d1a12fb191fff8627923f94e4c9ef686b2d2

Authored by YunaiV
1 parent b0b707dd

✨ feat(friend): 添加好友展示备注功能

yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendController.java
... ... @@ -75,7 +75,7 @@ public class ImFriendController {
75 75 }
76 76  
77 77 @PutMapping("/update")
78   - @Operation(summary = "更新好友信息(当前仅免打扰)")
  78 + @Operation(summary = "更新好友信息")
79 79 public CommonResult<Boolean> updateFriend(@Valid @RequestBody ImFriendUpdateReqVO reqVO) {
80 80 friendService.updateFriend(getLoginUserId(), reqVO);
81 81 return success(true);
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendRespVO.java
... ... @@ -23,6 +23,9 @@ public class ImFriendRespVO {
23 23 @Schema(description = "是否免打扰", example = "false")
24 24 private Boolean muted;
25 25  
  26 + @Schema(description = "好友展示备注(仅自己可见)", example = "老张")
  27 + private String displayName;
  28 +
26 29 @Schema(description = "好友状态(0=正常,1=已删除)", example = "0")
27 30 private Integer status;
28 31  
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/vo/ImFriendUpdateReqVO.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.im.controller.admin.friend.vo;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import jakarta.validation.constraints.NotNull;
  5 +import jakarta.validation.constraints.Size;
5 6 import lombok.Data;
6 7  
7 8 @Schema(description = "管理后台 - IM 好友更新 Request VO")
... ... @@ -12,8 +13,11 @@ public class ImFriendUpdateReqVO {
12 13 @NotNull(message = "好友用户编号不能为空")
13 14 private Long friendUserId;
14 15  
15   - @Schema(description = "是否免打扰", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
16   - @NotNull(message = "免打扰状态不能为空")
  16 + @Schema(description = "是否免打扰;不传表示不修改", example = "true")
17 17 private Boolean muted;
18 18  
  19 + @Schema(description = "好友展示备注(仅自己可见);不传表示不修改,传空串表示清空", example = "老张")
  20 + @Size(max = 16, message = "好友备注最多 16 个字符")
  21 + private String displayName;
  22 +
19 23 }
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/friend/ImFriendDO.java
... ... @@ -51,6 +51,10 @@ public class ImFriendDO extends BaseDO {
51 51 */
52 52 private Boolean muted;
53 53 /**
  54 + * 好友展示备注
  55 + */
  56 + private String displayName;
  57 + /**
54 58 * 好友状态
55 59 * <p>
56 60 * 枚举 {@link CommonStatusEnum}
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImpl.java
... ... @@ -84,8 +84,9 @@ public class ImFriendServiceImpl implements ImFriendService {
84 84 throw exception(FRIEND_NOT_FRIEND);
85 85 }
86 86  
87   - // 2. 更新好友属性(目前仅免打扰)
88   - imFriendMapper.updateById(new ImFriendDO().setId(friend.getId()).setMuted(reqVO.getMuted()));
  87 + // 2. 更新好友属性
  88 + imFriendMapper.updateById(new ImFriendDO().setId(friend.getId())
  89 + .setMuted(reqVO.getMuted()).setDisplayName(reqVO.getDisplayName()));
89 90  
90 91 // 3. 推送好友更新通知(多端同步)
91 92 imWebSocketService.sendPrivateMessageAsync(userId,
... ...
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImplTest.java
... ... @@ -112,6 +112,46 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest {
112 112 assertEquals(FRIEND_NOT_FRIEND.getCode(), exception.getCode());
113 113 }
114 114  
  115 + @Test
  116 + public void testUpdateFriend_displayNameOnly() {
  117 + // 准备:只传备注、不传 muted —— 走差量更新
  118 + ImFriendUpdateReqVO reqVO = new ImFriendUpdateReqVO();
  119 + reqVO.setFriendUserId(2L);
  120 + reqVO.setDisplayName("老张");
  121 + ImFriendDO friend = ImFriendDO.builder().id(100L).userId(1L).friendUserId(2L)
  122 + .muted(false).status(CommonStatusEnum.ENABLE.getStatus()).build();
  123 + when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(friend);
  124 +
  125 + // 调用
  126 + friendService.updateFriend(1L, reqVO);
  127 +
  128 + // 断言:updateById 收到 displayName 但没有 muted(MyBatis-Plus 靠 NOT_NULL 跳过)
  129 + ArgumentCaptor<ImFriendDO> captor = ArgumentCaptor.forClass(ImFriendDO.class);
  130 + verify(imFriendMapper).updateById(captor.capture());
  131 + assertEquals(100L, captor.getValue().getId());
  132 + assertEquals("老张", captor.getValue().getDisplayName());
  133 + assertNull(captor.getValue().getMuted());
  134 + // 断言:推送好友更新通知
  135 + verify(imWebSocketService).sendPrivateMessageAsync(eq(1L), any(ImPrivateMessageDTO.class));
  136 + }
  137 +
  138 + @Test
  139 + public void testUpdateFriend_emptyRequest() {
  140 + // 准备:muted 和 displayName 都不传 —— 短路返回,不打 SQL 也不发推送
  141 + ImFriendUpdateReqVO reqVO = new ImFriendUpdateReqVO();
  142 + reqVO.setFriendUserId(2L);
  143 + ImFriendDO friend = ImFriendDO.builder().id(100L).userId(1L).friendUserId(2L)
  144 + .muted(false).status(CommonStatusEnum.ENABLE.getStatus()).build();
  145 + when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(friend);
  146 +
  147 + // 调用
  148 + friendService.updateFriend(1L, reqVO);
  149 +
  150 + // 断言:没触发 SQL 更新 / 没发 WebSocket 推送
  151 + verify(imFriendMapper, never()).updateById(any(ImFriendDO.class));
  152 + verify(imWebSocketService, never()).sendPrivateMessageAsync(any(Long.class), any(ImPrivateMessageDTO.class));
  153 + }
  154 +
115 155 // ========== addFriend ==========
116 156  
117 157 @Test
... ...
yudao-module-im/src/test/resources/sql/create_tables.sql
... ... @@ -81,6 +81,7 @@ CREATE TABLE IF NOT EXISTS &quot;im_friend&quot; (
81 81 "user_id" bigint NOT NULL COMMENT '用户编号',
82 82 "friend_user_id" bigint NOT NULL COMMENT '好友用户编号',
83 83 "muted" bit DEFAULT FALSE COMMENT '是否免打扰',
  84 + "display_name" varchar(64) NOT NULL DEFAULT '' COMMENT '好友展示备注(仅自己可见)',
84 85 "status" tinyint NOT NULL COMMENT '好友状态',
85 86 "add_time" timestamp DEFAULT NULL COMMENT '添加好友时间',
86 87 "delete_time" timestamp DEFAULT NULL COMMENT '删除好友时间',
... ...