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,7 +75,7 @@ public class ImFriendController {
75 } 75 }
76 76
77 @PutMapping("/update") 77 @PutMapping("/update")
78 - @Operation(summary = "更新好友信息(当前仅免打扰)") 78 + @Operation(summary = "更新好友信息")
79 public CommonResult<Boolean> updateFriend(@Valid @RequestBody ImFriendUpdateReqVO reqVO) { 79 public CommonResult<Boolean> updateFriend(@Valid @RequestBody ImFriendUpdateReqVO reqVO) {
80 friendService.updateFriend(getLoginUserId(), reqVO); 80 friendService.updateFriend(getLoginUserId(), reqVO);
81 return success(true); 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,6 +23,9 @@ public class ImFriendRespVO {
23 @Schema(description = "是否免打扰", example = "false") 23 @Schema(description = "是否免打扰", example = "false")
24 private Boolean muted; 24 private Boolean muted;
25 25
  26 + @Schema(description = "好友展示备注(仅自己可见)", example = "老张")
  27 + private String displayName;
  28 +
26 @Schema(description = "好友状态(0=正常,1=已删除)", example = "0") 29 @Schema(description = "好友状态(0=正常,1=已删除)", example = "0")
27 private Integer status; 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,6 +2,7 @@ package cn.iocoder.yudao.module.im.controller.admin.friend.vo;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import jakarta.validation.constraints.NotNull; 4 import jakarta.validation.constraints.NotNull;
  5 +import jakarta.validation.constraints.Size;
5 import lombok.Data; 6 import lombok.Data;
6 7
7 @Schema(description = "管理后台 - IM 好友更新 Request VO") 8 @Schema(description = "管理后台 - IM 好友更新 Request VO")
@@ -12,8 +13,11 @@ public class ImFriendUpdateReqVO { @@ -12,8 +13,11 @@ public class ImFriendUpdateReqVO {
12 @NotNull(message = "好友用户编号不能为空") 13 @NotNull(message = "好友用户编号不能为空")
13 private Long friendUserId; 14 private Long friendUserId;
14 15
15 - @Schema(description = "是否免打扰", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")  
16 - @NotNull(message = "免打扰状态不能为空") 16 + @Schema(description = "是否免打扰;不传表示不修改", example = "true")
17 private Boolean muted; 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,6 +51,10 @@ public class ImFriendDO extends BaseDO {
51 */ 51 */
52 private Boolean muted; 52 private Boolean muted;
53 /** 53 /**
  54 + * 好友展示备注
  55 + */
  56 + private String displayName;
  57 + /**
54 * 好友状态 58 * 好友状态
55 * <p> 59 * <p>
56 * 枚举 {@link CommonStatusEnum} 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,8 +84,9 @@ public class ImFriendServiceImpl implements ImFriendService {
84 throw exception(FRIEND_NOT_FRIEND); 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 // 3. 推送好友更新通知(多端同步) 91 // 3. 推送好友更新通知(多端同步)
91 imWebSocketService.sendPrivateMessageAsync(userId, 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,6 +112,46 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest {
112 assertEquals(FRIEND_NOT_FRIEND.getCode(), exception.getCode()); 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 // ========== addFriend ========== 155 // ========== addFriend ==========
116 156
117 @Test 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,6 +81,7 @@ CREATE TABLE IF NOT EXISTS &quot;im_friend&quot; (
81 "user_id" bigint NOT NULL COMMENT '用户编号', 81 "user_id" bigint NOT NULL COMMENT '用户编号',
82 "friend_user_id" bigint NOT NULL COMMENT '好友用户编号', 82 "friend_user_id" bigint NOT NULL COMMENT '好友用户编号',
83 "muted" bit DEFAULT FALSE COMMENT '是否免打扰', 83 "muted" bit DEFAULT FALSE COMMENT '是否免打扰',
  84 + "display_name" varchar(64) NOT NULL DEFAULT '' COMMENT '好友展示备注(仅自己可见)',
84 "status" tinyint NOT NULL COMMENT '好友状态', 85 "status" tinyint NOT NULL COMMENT '好友状态',
85 "add_time" timestamp DEFAULT NULL COMMENT '添加好友时间', 86 "add_time" timestamp DEFAULT NULL COMMENT '添加好友时间',
86 "delete_time" timestamp DEFAULT NULL COMMENT '删除好友时间', 87 "delete_time" timestamp DEFAULT NULL COMMENT '删除好友时间',