Commit 96f2d1a12fb191fff8627923f94e4c9ef686b2d2
1 parent
b0b707dd
✨ feat(friend): 添加好友展示备注功能
Showing
7 changed files
with
58 additions
and
5 deletions
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 "im_friend" ( | @@ -81,6 +81,7 @@ CREATE TABLE IF NOT EXISTS "im_friend" ( | ||
| 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 '删除好友时间', |