Commit f5bec3eec687e356b31ac21648dfa3beb5c25dbf
1 parent
ae71b713
✨ feat(im): 初始化表情包 v0.3:第四把 review(增加表情管理的界面)
Showing
18 changed files
with
273 additions
and
71 deletions
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFaceUserItemController.java
| ... | ... | @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.im.controller.admin.face; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | -import cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem.ImFaceUserItemRespVO; | |
| 6 | -import cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem.ImFaceUserItemSaveReqVO; | |
| 5 | +import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemRespVO; | |
| 6 | +import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO; | |
| 7 | 7 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; |
| 8 | 8 | import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService; |
| 9 | 9 | import io.swagger.v3.oas.annotations.Operation; | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/pack/ImFacePackUserRespVO.java
| ... | ... | @@ -15,8 +15,8 @@ public class ImFacePackUserRespVO { |
| 15 | 15 | @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") |
| 16 | 16 | private String name; |
| 17 | 17 | |
| 18 | - @Schema(description = "表情包图标 URL", example = "https://cdn.example.com/face/pack/cat.png") | |
| 19 | - private String iconUrl; | |
| 18 | + @Schema(description = "表情包图标", example = "https://cdn.example.com/face/pack/cat.png") | |
| 19 | + private String icon; | |
| 20 | 20 | |
| 21 | 21 | @Schema(description = "表情列表", requiredMode = Schema.RequiredMode.REQUIRED) |
| 22 | 22 | private List<Item> items; | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemRespVO.java
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemSaveReqVO.java
| 1 | -package cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem; | |
| 1 | +// TODO @AI:java 规范,应该是 useritem | |
| 2 | +package cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem; | |
| 2 | 3 | |
| 3 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 5 | import jakarta.validation.constraints.NotBlank; |
| ... | ... | @@ -28,7 +29,4 @@ public class ImFaceUserItemSaveReqVO { |
| 28 | 29 | @NotNull(message = "渲染高度不能为空") |
| 29 | 30 | private Integer height; |
| 30 | 31 | |
| 31 | - @Schema(description = "来源消息编号(从消息「添加到表情」时传入;自己上传则不传)", example = "10086") | |
| 32 | - private Long sourceMessageId; | |
| 33 | - | |
| 34 | 32 | } | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFaceUserItemManagerController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.manager.face; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 6 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 7 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerRespVO; | |
| 9 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; | |
| 10 | +import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService; | |
| 11 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | |
| 12 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | |
| 13 | +import io.swagger.v3.oas.annotations.Operation; | |
| 14 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 15 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 16 | +import jakarta.annotation.Resource; | |
| 17 | +import jakarta.validation.Valid; | |
| 18 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 19 | +import org.springframework.validation.annotation.Validated; | |
| 20 | +import org.springframework.web.bind.annotation.*; | |
| 21 | + | |
| 22 | +import java.util.List; | |
| 23 | +import java.util.Map; | |
| 24 | + | |
| 25 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 26 | + | |
| 27 | +@Tag(name = "管理后台 - IM 用户表情") | |
| 28 | +@RestController | |
| 29 | +@RequestMapping("/im/manager/face-user-item") | |
| 30 | +@Validated | |
| 31 | +public class ImFaceUserItemManagerController { | |
| 32 | + | |
| 33 | + @Resource | |
| 34 | + private ImFaceUserItemService faceUserItemService; | |
| 35 | + @Resource | |
| 36 | + private AdminUserApi adminUserApi; | |
| 37 | + | |
| 38 | + @GetMapping("/page") | |
| 39 | + @Operation(summary = "获得用户表情分页") | |
| 40 | + @PreAuthorize("@ss.hasPermission('im:manager:face-user-item:query')") | |
| 41 | + public CommonResult<PageResult<ImFaceUserItemManagerRespVO>> getFaceUserItemPage( | |
| 42 | + @Valid ImFaceUserItemManagerPageReqVO pageReqVO) { | |
| 43 | + PageResult<ImFaceUserItemDO> pageResult = faceUserItemService.getFaceUserItemPage(pageReqVO); | |
| 44 | + // 关联回填用户昵称 | |
| 45 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( | |
| 46 | + CollectionUtils.convertSet(pageResult.getList(), ImFaceUserItemDO::getUserId)); | |
| 47 | + List<ImFaceUserItemManagerRespVO> voList = CollectionUtils.convertList(pageResult.getList(), item -> { | |
| 48 | + ImFaceUserItemManagerRespVO vo = BeanUtils.toBean(item, ImFaceUserItemManagerRespVO.class); | |
| 49 | + AdminUserRespDTO user = userMap.get(item.getUserId()); | |
| 50 | + if (user != null) { | |
| 51 | + vo.setUserNickname(user.getNickname()); | |
| 52 | + } | |
| 53 | + return vo; | |
| 54 | + }); | |
| 55 | + return success(new PageResult<>(voList, pageResult.getTotal())); | |
| 56 | + } | |
| 57 | + | |
| 58 | + @DeleteMapping("/delete") | |
| 59 | + @Operation(summary = "删除用户表情") | |
| 60 | + @Parameter(name = "id", description = "编号", required = true, example = "4096") | |
| 61 | + @PreAuthorize("@ss.hasPermission('im:manager:face-user-item:delete')") | |
| 62 | + public CommonResult<Boolean> deleteFaceUserItem(@RequestParam("id") Long id) { | |
| 63 | + faceUserItemService.deleteFaceUserItem(id); | |
| 64 | + return success(true); | |
| 65 | + } | |
| 66 | + | |
| 67 | +} | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemPageReqVO.java
| ... | ... | @@ -5,7 +5,6 @@ import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 5 | import lombok.Data; |
| 6 | 6 | import lombok.EqualsAndHashCode; |
| 7 | 7 | |
| 8 | -// TODO @AI:拆分到 vo/item 目录下,如果是 item 的话;更简练; | |
| 9 | 8 | @Schema(description = "管理后台 - IM 表情包项分页 Request VO") |
| 10 | 9 | @Data |
| 11 | 10 | @EqualsAndHashCode(callSuper = true) | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackRespVO.java
| ... | ... | @@ -15,8 +15,8 @@ public class ImFacePackRespVO { |
| 15 | 15 | @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") |
| 16 | 16 | private String name; |
| 17 | 17 | |
| 18 | - @Schema(description = "表情包图标 URL", example = "https://cdn.example.com/face/pack/cat.png") | |
| 19 | - private String iconUrl; | |
| 18 | + @Schema(description = "表情包图标", example = "https://cdn.example.com/face/pack/cat.png") | |
| 19 | + private String icon; | |
| 20 | 20 | |
| 21 | 21 | @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| 22 | 22 | private Integer sort; | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackSaveReqVO.java
| ... | ... | @@ -18,9 +18,9 @@ public class ImFacePackSaveReqVO { |
| 18 | 18 | @Size(max = 64, message = "表情包名称长度不能超过 64") |
| 19 | 19 | private String name; |
| 20 | 20 | |
| 21 | - @Schema(description = "表情包图标 URL", example = "https://cdn.example.com/face/pack/cat.png") | |
| 22 | - @Size(max = 512, message = "图标 URL 长度不能超过 512") | |
| 23 | - private String iconUrl; | |
| 21 | + @Schema(description = "表情包图标", example = "https://cdn.example.com/face/pack/cat.png") | |
| 22 | + @Size(max = 512, message = "图标长度不能超过 512") | |
| 23 | + private String icon; | |
| 24 | 24 | |
| 25 | 25 | @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| 26 | 26 | @NotNull(message = "排序不能为空") | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem; | |
| 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 ImFaceUserItemManagerPageReqVO extends PageParam { | |
| 17 | + | |
| 18 | + @Schema(description = "所属用户编号", example = "1024") | |
| 19 | + private Long userId; | |
| 20 | + | |
| 21 | + @Schema(description = "表情名,模糊匹配", example = "狗") | |
| 22 | + private String name; | |
| 23 | + | |
| 24 | + @Schema(description = "添加时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]") | |
| 25 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 26 | + private LocalDateTime[] createTime; | |
| 27 | + | |
| 28 | +} | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem; | |
| 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 ImFaceUserItemManagerRespVO { | |
| 11 | + | |
| 12 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") | |
| 13 | + private Long id; | |
| 14 | + | |
| 15 | + @Schema(description = "所属用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 16 | + private Long userId; | |
| 17 | + | |
| 18 | + @Schema(description = "所属用户昵称", example = "张三") | |
| 19 | + private String userNickname; | |
| 20 | + | |
| 21 | + @Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED, | |
| 22 | + example = "https://cdn.example.com/face/user/abc.gif") | |
| 23 | + private String url; | |
| 24 | + | |
| 25 | + @Schema(description = "表情名", example = "狗头") | |
| 26 | + private String name; | |
| 27 | + | |
| 28 | + @Schema(description = "渲染宽度(像素)", example = "200") | |
| 29 | + private Integer width; | |
| 30 | + | |
| 31 | + @Schema(description = "渲染高度(像素)", example = "200") | |
| 32 | + private Integer height; | |
| 33 | + | |
| 34 | + @Schema(description = "添加时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 35 | + private LocalDateTime createTime; | |
| 36 | + | |
| 37 | +} | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackDO.java
| ... | ... | @@ -31,13 +31,12 @@ public class ImFacePackDO extends BaseDO { |
| 31 | 31 | * 表情包名称 |
| 32 | 32 | */ |
| 33 | 33 | private String name; |
| 34 | - // TODO @AI:icon 一般不带 url;类似 avatar,特有单词; | |
| 35 | 34 | /** |
| 36 | - * 表情包图标 URL | |
| 35 | + * 表情包图标 | |
| 37 | 36 | * <p> |
| 38 | 37 | * 面板底部 tab 栏显示 |
| 39 | 38 | */ |
| 40 | - private String iconUrl; | |
| 39 | + private String icon; | |
| 41 | 40 | /** |
| 42 | 41 | * 排序 |
| 43 | 42 | */ | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFaceUserItemDO.java
| ... | ... | @@ -28,8 +28,8 @@ public class ImFaceUserItemDO extends BaseDO { |
| 28 | 28 | private Long id; |
| 29 | 29 | /** |
| 30 | 30 | * 所属用户编号 |
| 31 | - * | |
| 32 | - * // TODO @AI:是不是要关联下 userid | |
| 31 | + * <p> | |
| 32 | + * 关联 AdminUserDO 的 id 编号 | |
| 33 | 33 | */ |
| 34 | 34 | private Long userId; |
| 35 | 35 | /** |
| ... | ... | @@ -51,14 +51,6 @@ public class ImFaceUserItemDO extends BaseDO { |
| 51 | 51 | */ |
| 52 | 52 | private Integer height; |
| 53 | 53 | /** |
| 54 | - * 来源消息编号 | |
| 55 | - * <p> | |
| 56 | - * 从消息「添加到表情」时记录;自己上传则为 NULL;用于排查 / 后续溯源 | |
| 57 | - * | |
| 58 | - * TODO @AI:关联字段; | |
| 59 | - */ | |
| 60 | - private Long sourceMessageId; | |
| 61 | - /** | |
| 62 | 54 | * 排序 |
| 63 | 55 | */ |
| 64 | 56 | private Integer sort; | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java
| 1 | 1 | package cn.iocoder.yudao.module.im.dal.mysql.face; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 3 | 4 | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; |
| 4 | 5 | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| 6 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO; | |
| 5 | 7 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; |
| 6 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 7 | 9 | |
| ... | ... | @@ -15,7 +17,6 @@ import java.util.List; |
| 15 | 17 | @Mapper |
| 16 | 18 | public interface ImFaceUserItemMapper extends BaseMapperX<ImFaceUserItemDO> { |
| 17 | 19 | |
| 18 | - /** 取用户的所有个人表情,按 sort 升序、id 倒序(最近添加在前) */ | |
| 19 | 20 | default List<ImFaceUserItemDO> selectListByUserId(Long userId) { |
| 20 | 21 | return selectList(new LambdaQueryWrapperX<ImFaceUserItemDO>() |
| 21 | 22 | .eq(ImFaceUserItemDO::getUserId, userId) |
| ... | ... | @@ -23,15 +24,18 @@ public interface ImFaceUserItemMapper extends BaseMapperX<ImFaceUserItemDO> { |
| 23 | 24 | .orderByDesc(ImFaceUserItemDO::getId)); |
| 24 | 25 | } |
| 25 | 26 | |
| 26 | - default Long selectCountByUserId(Long userId) { | |
| 27 | - return selectCount(new LambdaQueryWrapperX<ImFaceUserItemDO>() | |
| 28 | - .eq(ImFaceUserItemDO::getUserId, userId)); | |
| 29 | - } | |
| 30 | - | |
| 31 | 27 | default ImFaceUserItemDO selectByUserIdAndUrl(Long userId, String url) { |
| 32 | 28 | return selectOne(new LambdaQueryWrapperX<ImFaceUserItemDO>() |
| 33 | 29 | .eq(ImFaceUserItemDO::getUserId, userId) |
| 34 | 30 | .eq(ImFaceUserItemDO::getUrl, url)); |
| 35 | 31 | } |
| 36 | 32 | |
| 33 | + default PageResult<ImFaceUserItemDO> selectPage(ImFaceUserItemManagerPageReqVO reqVO) { | |
| 34 | + return selectPage(reqVO, new LambdaQueryWrapperX<ImFaceUserItemDO>() | |
| 35 | + .eqIfPresent(ImFaceUserItemDO::getUserId, reqVO.getUserId()) | |
| 36 | + .likeIfPresent(ImFaceUserItemDO::getName, reqVO.getName()) | |
| 37 | + .betweenIfPresent(ImFaceUserItemDO::getCreateTime, reqVO.getCreateTime()) | |
| 38 | + .orderByDesc(ImFaceUserItemDO::getId)); | |
| 39 | + } | |
| 40 | + | |
| 37 | 41 | } | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java
| ... | ... | @@ -9,8 +9,6 @@ import jakarta.validation.Valid; |
| 9 | 9 | import java.util.Collection; |
| 10 | 10 | import java.util.List; |
| 11 | 11 | |
| 12 | -// TODO @AI:已经分了用户端、和管理后台,注释上就不用写【用户端】【【管理后台】】了。。。 | |
| 13 | -// TODO @AI:注释的风格,参考下别的模块,一些 params、return 都要写呀; | |
| 14 | 12 | /** |
| 15 | 13 | * IM 表情包项 Service 接口 |
| 16 | 14 | * |
| ... | ... | @@ -21,49 +19,73 @@ public interface ImFacePackItemService { |
| 21 | 19 | // ==================== 用户端 ==================== |
| 22 | 20 | |
| 23 | 21 | /** |
| 24 | - * 【用户端】按 packIds 批量取启用项,给前端聚合接口用 | |
| 22 | + * 按 packIds 批量取启用项,给前端聚合接口用 | |
| 23 | + * | |
| 24 | + * @param packIds 表情包编号列表 | |
| 25 | + * @return 启用状态的表情列表 | |
| 25 | 26 | */ |
| 26 | 27 | List<ImFacePackItemDO> getEnabledItemListByPackIds(Collection<Long> packIds); |
| 27 | 28 | |
| 28 | 29 | /** |
| 29 | 30 | * 取某个表情包下的表情数量;ImFacePackService 删除前校验「包下无项」用 |
| 31 | + * | |
| 32 | + * @param packId 表情包编号 | |
| 33 | + * @return 数量 | |
| 30 | 34 | */ |
| 31 | 35 | Long getFacePackItemCount(Long packId); |
| 32 | 36 | |
| 33 | 37 | /** |
| 34 | 38 | * 取多个表情包下的表情数量合计;ImFacePackService 批量删除前校验用 |
| 39 | + * | |
| 40 | + * @param packIds 表情包编号列表 | |
| 41 | + * @return 数量合计 | |
| 35 | 42 | */ |
| 36 | 43 | Long getFacePackItemCount(Collection<Long> packIds); |
| 37 | 44 | |
| 38 | 45 | // ==================== 管理后台 ==================== |
| 39 | 46 | |
| 40 | 47 | /** |
| 41 | - * 【管理后台】分页查询 | |
| 48 | + * 分页查询表情包项 | |
| 49 | + * | |
| 50 | + * @param reqVO 分页查询条件 | |
| 51 | + * @return 表情包项分页 | |
| 42 | 52 | */ |
| 43 | 53 | PageResult<ImFacePackItemDO> getFacePackItemPage(ImFacePackItemPageReqVO reqVO); |
| 44 | 54 | |
| 45 | 55 | /** |
| 46 | - * 【管理后台】获取详情 | |
| 56 | + * 获取表情包项详情 | |
| 57 | + * | |
| 58 | + * @param id 表情包项编号 | |
| 59 | + * @return 表情包项 DO | |
| 47 | 60 | */ |
| 48 | 61 | ImFacePackItemDO getFacePackItem(Long id); |
| 49 | 62 | |
| 50 | 63 | /** |
| 51 | - * 【管理后台】新增,返回新增 id | |
| 64 | + * 新增表情包项 | |
| 65 | + * | |
| 66 | + * @param reqVO 新增请求 | |
| 67 | + * @return 新增表情包项编号 | |
| 52 | 68 | */ |
| 53 | 69 | Long createFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); |
| 54 | 70 | |
| 55 | 71 | /** |
| 56 | - * 【管理后台】修改 | |
| 72 | + * 修改表情包项 | |
| 73 | + * | |
| 74 | + * @param reqVO 修改请求 | |
| 57 | 75 | */ |
| 58 | 76 | void updateFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); |
| 59 | 77 | |
| 60 | 78 | /** |
| 61 | - * 【管理后台】删除 | |
| 79 | + * 删除表情包项 | |
| 80 | + * | |
| 81 | + * @param id 表情包项编号 | |
| 62 | 82 | */ |
| 63 | 83 | void deleteFacePackItem(Long id); |
| 64 | 84 | |
| 65 | 85 | /** |
| 66 | - * 【管理后台】批量删除 | |
| 86 | + * 批量删除表情包项 | |
| 87 | + * | |
| 88 | + * @param ids 表情包项编号列表 | |
| 67 | 89 | */ |
| 68 | 90 | void deleteFacePackItemList(List<Long> ids); |
| 69 | 91 | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java
| ... | ... | @@ -15,17 +15,20 @@ import java.util.List; |
| 15 | 15 | */ |
| 16 | 16 | public interface ImFacePackService { |
| 17 | 17 | |
| 18 | - // TODO @AI:已经区分了 === 就不用写【用户端】【管理后台】了。 | |
| 19 | - | |
| 20 | 18 | // ==================== 用户端 ==================== |
| 21 | 19 | |
| 22 | 20 | /** |
| 23 | - * 【用户端】获取所有启用的表情包,按 sort 升序 | |
| 21 | + * 获取所有启用的表情包,按 sort 升序 | |
| 22 | + * | |
| 23 | + * @return 启用的表情包列表 | |
| 24 | 24 | */ |
| 25 | 25 | List<ImFacePackDO> getEnabledFacePackList(); |
| 26 | 26 | |
| 27 | 27 | /** |
| 28 | 28 | * 校验表情包存在 |
| 29 | + * | |
| 30 | + * @param id 表情包编号 | |
| 31 | + * @return 表情包 DO | |
| 29 | 32 | */ |
| 30 | 33 | @SuppressWarnings("UnusedReturnValue") |
| 31 | 34 | ImFacePackDO validateFacePackExists(Long id); |
| ... | ... | @@ -33,32 +36,47 @@ public interface ImFacePackService { |
| 33 | 36 | // ==================== 管理后台 ==================== |
| 34 | 37 | |
| 35 | 38 | /** |
| 36 | - * 【管理后台】分页查询表情包 | |
| 39 | + * 分页查询表情包 | |
| 40 | + * | |
| 41 | + * @param reqVO 分页查询条件 | |
| 42 | + * @return 表情包分页 | |
| 37 | 43 | */ |
| 38 | 44 | PageResult<ImFacePackDO> getFacePackPage(ImFacePackPageReqVO reqVO); |
| 39 | 45 | |
| 40 | 46 | /** |
| 41 | - * 【管理后台】获取表情包详情 | |
| 47 | + * 获取表情包详情 | |
| 48 | + * | |
| 49 | + * @param id 表情包编号 | |
| 50 | + * @return 表情包 DO | |
| 42 | 51 | */ |
| 43 | 52 | ImFacePackDO getFacePack(Long id); |
| 44 | 53 | |
| 45 | 54 | /** |
| 46 | - * 【管理后台】新增表情包,返回新增 id | |
| 55 | + * 新增表情包 | |
| 56 | + * | |
| 57 | + * @param reqVO 新增请求 | |
| 58 | + * @return 新增表情包编号 | |
| 47 | 59 | */ |
| 48 | 60 | Long createFacePack(@Valid ImFacePackSaveReqVO reqVO); |
| 49 | 61 | |
| 50 | 62 | /** |
| 51 | - * 【管理后台】修改表情包 | |
| 63 | + * 修改表情包 | |
| 64 | + * | |
| 65 | + * @param reqVO 修改请求 | |
| 52 | 66 | */ |
| 53 | 67 | void updateFacePack(@Valid ImFacePackSaveReqVO reqVO); |
| 54 | 68 | |
| 55 | 69 | /** |
| 56 | - * 【管理后台】删除表情包;存在表情时拒绝 | |
| 70 | + * 删除表情包;包下存在表情时拒绝,避免历史 face 消息无法回查归属 | |
| 71 | + * | |
| 72 | + * @param id 表情包编号 | |
| 57 | 73 | */ |
| 58 | 74 | void deleteFacePack(Long id); |
| 59 | 75 | |
| 60 | 76 | /** |
| 61 | - * 【管理后台】批量删除表情包 | |
| 77 | + * 批量删除表情包;任一包下存在表情时整批拒绝,避免「只删一半」中间态 | |
| 78 | + * | |
| 79 | + * @param ids 表情包编号列表 | |
| 62 | 80 | */ |
| 63 | 81 | void deleteFacePackList(List<Long> ids); |
| 64 | 82 | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java
| 1 | 1 | package cn.iocoder.yudao.module.im.service.face; |
| 2 | 2 | |
| 3 | -import cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem.ImFaceUserItemSaveReqVO; | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO; | |
| 5 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO; | |
| 4 | 6 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; |
| 5 | 7 | import jakarta.validation.Valid; |
| 6 | 8 | |
| ... | ... | @@ -15,19 +17,44 @@ public interface ImFaceUserItemService { |
| 15 | 17 | |
| 16 | 18 | /** |
| 17 | 19 | * 获取指定用户的个人表情列表 |
| 20 | + * | |
| 21 | + * @param userId 用户编号 | |
| 22 | + * @return 个人表情列表 | |
| 18 | 23 | */ |
| 19 | 24 | List<ImFaceUserItemDO> getFaceUserItemList(Long userId); |
| 20 | 25 | |
| 21 | 26 | /** |
| 22 | - * 添加个人表情;返回新增记录 id | |
| 23 | - * <p> | |
| 24 | - * 同 URL 重复添加抛 FACE_USER_ITEM_DUPLICATED;表上 (user_id, url) 唯一约束兜底并发 race | |
| 27 | + * 添加个人表情 | |
| 28 | + * | |
| 29 | + * @param userId 用户编号 | |
| 30 | + * @param reqVO 添加请求 | |
| 31 | + * @return 新增表情编号 | |
| 25 | 32 | */ |
| 26 | 33 | Long createFaceUserItem(Long userId, @Valid ImFaceUserItemSaveReqVO reqVO); |
| 27 | 34 | |
| 28 | 35 | /** |
| 29 | 36 | * 删除指定用户的某条个人表情 |
| 37 | + * | |
| 38 | + * @param userId 用户编号 | |
| 39 | + * @param id 表情编号 | |
| 30 | 40 | */ |
| 31 | 41 | void deleteFaceUserItem(Long userId, Long id); |
| 32 | 42 | |
| 43 | + // ==================== 管理后台 ==================== | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 分页查询所有用户的个人表情;管理后台审计 / 删除违规图用 | |
| 47 | + * | |
| 48 | + * @param reqVO 分页查询条件 | |
| 49 | + * @return 个人表情分页 | |
| 50 | + */ | |
| 51 | + PageResult<ImFaceUserItemDO> getFaceUserItemPage(ImFaceUserItemManagerPageReqVO reqVO); | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 管理后台直接删除某条个人表情;不做归属校验 | |
| 55 | + * | |
| 56 | + * @param id 表情编号 | |
| 57 | + */ | |
| 58 | + void deleteFaceUserItem(Long id); | |
| 59 | + | |
| 33 | 60 | } | ... | ... |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.im.service.face; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.ObjectUtil; |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | 5 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 5 | -import cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem.ImFaceUserItemSaveReqVO; | |
| 6 | +import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO; | |
| 7 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO; | |
| 6 | 8 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; |
| 7 | 9 | import cn.iocoder.yudao.module.im.dal.mysql.face.ImFaceUserItemMapper; |
| 8 | 10 | import jakarta.annotation.Resource; |
| 9 | -import org.springframework.dao.DuplicateKeyException; | |
| 10 | 11 | import org.springframework.stereotype.Service; |
| 11 | 12 | import org.springframework.validation.annotation.Validated; |
| 12 | 13 | |
| ... | ... | @@ -41,15 +42,9 @@ public class ImFaceUserItemServiceImpl implements ImFaceUserItemService { |
| 41 | 42 | throw exception(FACE_USER_ITEM_DUPLICATED); |
| 42 | 43 | } |
| 43 | 44 | |
| 44 | - // 2. 入库;表 (user_id, url, tenant_id) 唯一约束兜底并发 race —— 两个请求同时过 step 1 时 DB 拦截 | |
| 45 | - // TODO @AI:不加唯一索引。不然删除后恢复麻烦。按照我说的来。 | |
| 46 | - ImFaceUserItemDO item = BeanUtils.toBean(reqVO, ImFaceUserItemDO.class) | |
| 47 | - .setUserId(userId); | |
| 48 | - try { | |
| 49 | - faceUserItemMapper.insert(item); | |
| 50 | - } catch (DuplicateKeyException ignored) { | |
| 51 | - throw exception(FACE_USER_ITEM_DUPLICATED); | |
| 52 | - } | |
| 45 | + // 2. 入库 | |
| 46 | + ImFaceUserItemDO item = BeanUtils.toBean(reqVO, ImFaceUserItemDO.class).setUserId(userId); | |
| 47 | + faceUserItemMapper.insert(item); | |
| 53 | 48 | return item.getId(); |
| 54 | 49 | } |
| 55 | 50 | |
| ... | ... | @@ -69,4 +64,22 @@ public class ImFaceUserItemServiceImpl implements ImFaceUserItemService { |
| 69 | 64 | faceUserItemMapper.deleteById(id); |
| 70 | 65 | } |
| 71 | 66 | |
| 67 | + // ==================== 管理后台 ==================== | |
| 68 | + | |
| 69 | + @Override | |
| 70 | + public PageResult<ImFaceUserItemDO> getFaceUserItemPage(ImFaceUserItemManagerPageReqVO reqVO) { | |
| 71 | + return faceUserItemMapper.selectPage(reqVO); | |
| 72 | + } | |
| 73 | + | |
| 74 | + @Override | |
| 75 | + public void deleteFaceUserItem(Long id) { | |
| 76 | + // 1. 校验存在 | |
| 77 | + if (faceUserItemMapper.selectById(id) == null) { | |
| 78 | + throw exception(FACE_USER_ITEM_NOT_EXISTS); | |
| 79 | + } | |
| 80 | + | |
| 81 | + // 2. 删除 | |
| 82 | + faceUserItemMapper.deleteById(id); | |
| 83 | + } | |
| 84 | + | |
| 72 | 85 | } | ... | ... |
yudao-module-im/src/test/resources/sql/create_tables.sql
| ... | ... | @@ -149,7 +149,7 @@ CREATE TABLE IF NOT EXISTS "im_group_request" ( |
| 149 | 149 | CREATE TABLE IF NOT EXISTS "im_face_pack" ( |
| 150 | 150 | "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号', |
| 151 | 151 | "name" varchar(64) NOT NULL COMMENT '表情包名称', |
| 152 | - "icon_url" varchar(512) DEFAULT NULL COMMENT '表情包图标 URL(面板底部 tab 显示)', | |
| 152 | + "icon" varchar(512) DEFAULT NULL COMMENT '表情包图标(面板底部 tab 显示)', | |
| 153 | 153 | "sort" int NOT NULL DEFAULT 0 COMMENT '排序', |
| 154 | 154 | "status" tinyint NOT NULL COMMENT '状态', |
| 155 | 155 | "creator" varchar(64) DEFAULT '', |
| ... | ... | @@ -186,7 +186,6 @@ CREATE TABLE IF NOT EXISTS "im_face_user_item" ( |
| 186 | 186 | "name" varchar(64) DEFAULT NULL COMMENT '表情名(可选)', |
| 187 | 187 | "width" int NOT NULL DEFAULT 0 COMMENT '渲染宽度(像素)', |
| 188 | 188 | "height" int NOT NULL DEFAULT 0 COMMENT '渲染高度(像素)', |
| 189 | - "source_message_id" bigint DEFAULT NULL COMMENT '来源消息编号(从消息「添加到表情」时记录;自己上传则为 NULL)', | |
| 190 | 189 | "sort" int NOT NULL DEFAULT 0 COMMENT '排序', |
| 191 | 190 | "creator" varchar(64) DEFAULT '', |
| 192 | 191 | "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, |
| ... | ... | @@ -194,6 +193,5 @@ CREATE TABLE IF NOT EXISTS "im_face_user_item" ( |
| 194 | 193 | "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, |
| 195 | 194 | "deleted" bit NOT NULL DEFAULT FALSE, |
| 196 | 195 | "tenant_id" bigint NOT NULL DEFAULT 0, |
| 197 | - PRIMARY KEY ("id"), | |
| 198 | - CONSTRAINT "uk_im_face_user_item_user_url" UNIQUE ("user_id", "url", "tenant_id") | |
| 196 | + PRIMARY KEY ("id") | |
| 199 | 197 | ) COMMENT 'IM 用户私有表情表'; | ... | ... |