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,8 +2,8 @@ package cn.iocoder.yudao.module.im.controller.admin.face; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 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 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; | 7 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; |
| 8 | import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService; | 8 | import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService; |
| 9 | import io.swagger.v3.oas.annotations.Operation; | 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,8 +15,8 @@ public class ImFacePackUserRespVO { | ||
| 15 | @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") | 15 | @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") |
| 16 | private String name; | 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 | @Schema(description = "表情列表", requiredMode = Schema.RequiredMode.REQUIRED) | 21 | @Schema(description = "表情列表", requiredMode = Schema.RequiredMode.REQUIRED) |
| 22 | private List<Item> items; | 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 | import io.swagger.v3.oas.annotations.media.Schema; | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import jakarta.validation.constraints.NotBlank; | 5 | import jakarta.validation.constraints.NotBlank; |
| @@ -28,7 +29,4 @@ public class ImFaceUserItemSaveReqVO { | @@ -28,7 +29,4 @@ public class ImFaceUserItemSaveReqVO { | ||
| 28 | @NotNull(message = "渲染高度不能为空") | 29 | @NotNull(message = "渲染高度不能为空") |
| 29 | private Integer height; | 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,7 +5,6 @@ import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | import lombok.Data; | 5 | import lombok.Data; |
| 6 | import lombok.EqualsAndHashCode; | 6 | import lombok.EqualsAndHashCode; |
| 7 | 7 | ||
| 8 | -// TODO @AI:拆分到 vo/item 目录下,如果是 item 的话;更简练; | ||
| 9 | @Schema(description = "管理后台 - IM 表情包项分页 Request VO") | 8 | @Schema(description = "管理后台 - IM 表情包项分页 Request VO") |
| 10 | @Data | 9 | @Data |
| 11 | @EqualsAndHashCode(callSuper = true) | 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,8 +15,8 @@ public class ImFacePackRespVO { | ||
| 15 | @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") | 15 | @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") |
| 16 | private String name; | 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 | @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | 21 | @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| 22 | private Integer sort; | 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,9 +18,9 @@ public class ImFacePackSaveReqVO { | ||
| 18 | @Size(max = 64, message = "表情包名称长度不能超过 64") | 18 | @Size(max = 64, message = "表情包名称长度不能超过 64") |
| 19 | private String name; | 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 | @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | 25 | @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") |
| 26 | @NotNull(message = "排序不能为空") | 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,13 +31,12 @@ public class ImFacePackDO extends BaseDO { | ||
| 31 | * 表情包名称 | 31 | * 表情包名称 |
| 32 | */ | 32 | */ |
| 33 | private String name; | 33 | private String name; |
| 34 | - // TODO @AI:icon 一般不带 url;类似 avatar,特有单词; | ||
| 35 | /** | 34 | /** |
| 36 | - * 表情包图标 URL | 35 | + * 表情包图标 |
| 37 | * <p> | 36 | * <p> |
| 38 | * 面板底部 tab 栏显示 | 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,8 +28,8 @@ public class ImFaceUserItemDO extends BaseDO { | ||
| 28 | private Long id; | 28 | private Long id; |
| 29 | /** | 29 | /** |
| 30 | * 所属用户编号 | 30 | * 所属用户编号 |
| 31 | - * | ||
| 32 | - * // TODO @AI:是不是要关联下 userid | 31 | + * <p> |
| 32 | + * 关联 AdminUserDO 的 id 编号 | ||
| 33 | */ | 33 | */ |
| 34 | private Long userId; | 34 | private Long userId; |
| 35 | /** | 35 | /** |
| @@ -51,14 +51,6 @@ public class ImFaceUserItemDO extends BaseDO { | @@ -51,14 +51,6 @@ public class ImFaceUserItemDO extends BaseDO { | ||
| 51 | */ | 51 | */ |
| 52 | private Integer height; | 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 | private Integer sort; | 56 | private Integer sort; |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java
| 1 | package cn.iocoder.yudao.module.im.dal.mysql.face; | 1 | package cn.iocoder.yudao.module.im.dal.mysql.face; |
| 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.face.vo.useritem.ImFaceUserItemManagerPageReqVO; | ||
| 5 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; | 7 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; |
| 6 | import org.apache.ibatis.annotations.Mapper; | 8 | import org.apache.ibatis.annotations.Mapper; |
| 7 | 9 | ||
| @@ -15,7 +17,6 @@ import java.util.List; | @@ -15,7 +17,6 @@ import java.util.List; | ||
| 15 | @Mapper | 17 | @Mapper |
| 16 | public interface ImFaceUserItemMapper extends BaseMapperX<ImFaceUserItemDO> { | 18 | public interface ImFaceUserItemMapper extends BaseMapperX<ImFaceUserItemDO> { |
| 17 | 19 | ||
| 18 | - /** 取用户的所有个人表情,按 sort 升序、id 倒序(最近添加在前) */ | ||
| 19 | default List<ImFaceUserItemDO> selectListByUserId(Long userId) { | 20 | default List<ImFaceUserItemDO> selectListByUserId(Long userId) { |
| 20 | return selectList(new LambdaQueryWrapperX<ImFaceUserItemDO>() | 21 | return selectList(new LambdaQueryWrapperX<ImFaceUserItemDO>() |
| 21 | .eq(ImFaceUserItemDO::getUserId, userId) | 22 | .eq(ImFaceUserItemDO::getUserId, userId) |
| @@ -23,15 +24,18 @@ public interface ImFaceUserItemMapper extends BaseMapperX<ImFaceUserItemDO> { | @@ -23,15 +24,18 @@ public interface ImFaceUserItemMapper extends BaseMapperX<ImFaceUserItemDO> { | ||
| 23 | .orderByDesc(ImFaceUserItemDO::getId)); | 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 | default ImFaceUserItemDO selectByUserIdAndUrl(Long userId, String url) { | 27 | default ImFaceUserItemDO selectByUserIdAndUrl(Long userId, String url) { |
| 32 | return selectOne(new LambdaQueryWrapperX<ImFaceUserItemDO>() | 28 | return selectOne(new LambdaQueryWrapperX<ImFaceUserItemDO>() |
| 33 | .eq(ImFaceUserItemDO::getUserId, userId) | 29 | .eq(ImFaceUserItemDO::getUserId, userId) |
| 34 | .eq(ImFaceUserItemDO::getUrl, url)); | 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,8 +9,6 @@ import jakarta.validation.Valid; | ||
| 9 | import java.util.Collection; | 9 | import java.util.Collection; |
| 10 | import java.util.List; | 10 | import java.util.List; |
| 11 | 11 | ||
| 12 | -// TODO @AI:已经分了用户端、和管理后台,注释上就不用写【用户端】【【管理后台】】了。。。 | ||
| 13 | -// TODO @AI:注释的风格,参考下别的模块,一些 params、return 都要写呀; | ||
| 14 | /** | 12 | /** |
| 15 | * IM 表情包项 Service 接口 | 13 | * IM 表情包项 Service 接口 |
| 16 | * | 14 | * |
| @@ -21,49 +19,73 @@ public interface ImFacePackItemService { | @@ -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 | List<ImFacePackItemDO> getEnabledItemListByPackIds(Collection<Long> packIds); | 27 | List<ImFacePackItemDO> getEnabledItemListByPackIds(Collection<Long> packIds); |
| 27 | 28 | ||
| 28 | /** | 29 | /** |
| 29 | * 取某个表情包下的表情数量;ImFacePackService 删除前校验「包下无项」用 | 30 | * 取某个表情包下的表情数量;ImFacePackService 删除前校验「包下无项」用 |
| 31 | + * | ||
| 32 | + * @param packId 表情包编号 | ||
| 33 | + * @return 数量 | ||
| 30 | */ | 34 | */ |
| 31 | Long getFacePackItemCount(Long packId); | 35 | Long getFacePackItemCount(Long packId); |
| 32 | 36 | ||
| 33 | /** | 37 | /** |
| 34 | * 取多个表情包下的表情数量合计;ImFacePackService 批量删除前校验用 | 38 | * 取多个表情包下的表情数量合计;ImFacePackService 批量删除前校验用 |
| 39 | + * | ||
| 40 | + * @param packIds 表情包编号列表 | ||
| 41 | + * @return 数量合计 | ||
| 35 | */ | 42 | */ |
| 36 | Long getFacePackItemCount(Collection<Long> packIds); | 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 | PageResult<ImFacePackItemDO> getFacePackItemPage(ImFacePackItemPageReqVO reqVO); | 53 | PageResult<ImFacePackItemDO> getFacePackItemPage(ImFacePackItemPageReqVO reqVO); |
| 44 | 54 | ||
| 45 | /** | 55 | /** |
| 46 | - * 【管理后台】获取详情 | 56 | + * 获取表情包项详情 |
| 57 | + * | ||
| 58 | + * @param id 表情包项编号 | ||
| 59 | + * @return 表情包项 DO | ||
| 47 | */ | 60 | */ |
| 48 | ImFacePackItemDO getFacePackItem(Long id); | 61 | ImFacePackItemDO getFacePackItem(Long id); |
| 49 | 62 | ||
| 50 | /** | 63 | /** |
| 51 | - * 【管理后台】新增,返回新增 id | 64 | + * 新增表情包项 |
| 65 | + * | ||
| 66 | + * @param reqVO 新增请求 | ||
| 67 | + * @return 新增表情包项编号 | ||
| 52 | */ | 68 | */ |
| 53 | Long createFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); | 69 | Long createFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); |
| 54 | 70 | ||
| 55 | /** | 71 | /** |
| 56 | - * 【管理后台】修改 | 72 | + * 修改表情包项 |
| 73 | + * | ||
| 74 | + * @param reqVO 修改请求 | ||
| 57 | */ | 75 | */ |
| 58 | void updateFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); | 76 | void updateFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); |
| 59 | 77 | ||
| 60 | /** | 78 | /** |
| 61 | - * 【管理后台】删除 | 79 | + * 删除表情包项 |
| 80 | + * | ||
| 81 | + * @param id 表情包项编号 | ||
| 62 | */ | 82 | */ |
| 63 | void deleteFacePackItem(Long id); | 83 | void deleteFacePackItem(Long id); |
| 64 | 84 | ||
| 65 | /** | 85 | /** |
| 66 | - * 【管理后台】批量删除 | 86 | + * 批量删除表情包项 |
| 87 | + * | ||
| 88 | + * @param ids 表情包项编号列表 | ||
| 67 | */ | 89 | */ |
| 68 | void deleteFacePackItemList(List<Long> ids); | 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,17 +15,20 @@ import java.util.List; | ||
| 15 | */ | 15 | */ |
| 16 | public interface ImFacePackService { | 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 | List<ImFacePackDO> getEnabledFacePackList(); | 25 | List<ImFacePackDO> getEnabledFacePackList(); |
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| 28 | * 校验表情包存在 | 28 | * 校验表情包存在 |
| 29 | + * | ||
| 30 | + * @param id 表情包编号 | ||
| 31 | + * @return 表情包 DO | ||
| 29 | */ | 32 | */ |
| 30 | @SuppressWarnings("UnusedReturnValue") | 33 | @SuppressWarnings("UnusedReturnValue") |
| 31 | ImFacePackDO validateFacePackExists(Long id); | 34 | ImFacePackDO validateFacePackExists(Long id); |
| @@ -33,32 +36,47 @@ public interface ImFacePackService { | @@ -33,32 +36,47 @@ public interface ImFacePackService { | ||
| 33 | // ==================== 管理后台 ==================== | 36 | // ==================== 管理后台 ==================== |
| 34 | 37 | ||
| 35 | /** | 38 | /** |
| 36 | - * 【管理后台】分页查询表情包 | 39 | + * 分页查询表情包 |
| 40 | + * | ||
| 41 | + * @param reqVO 分页查询条件 | ||
| 42 | + * @return 表情包分页 | ||
| 37 | */ | 43 | */ |
| 38 | PageResult<ImFacePackDO> getFacePackPage(ImFacePackPageReqVO reqVO); | 44 | PageResult<ImFacePackDO> getFacePackPage(ImFacePackPageReqVO reqVO); |
| 39 | 45 | ||
| 40 | /** | 46 | /** |
| 41 | - * 【管理后台】获取表情包详情 | 47 | + * 获取表情包详情 |
| 48 | + * | ||
| 49 | + * @param id 表情包编号 | ||
| 50 | + * @return 表情包 DO | ||
| 42 | */ | 51 | */ |
| 43 | ImFacePackDO getFacePack(Long id); | 52 | ImFacePackDO getFacePack(Long id); |
| 44 | 53 | ||
| 45 | /** | 54 | /** |
| 46 | - * 【管理后台】新增表情包,返回新增 id | 55 | + * 新增表情包 |
| 56 | + * | ||
| 57 | + * @param reqVO 新增请求 | ||
| 58 | + * @return 新增表情包编号 | ||
| 47 | */ | 59 | */ |
| 48 | Long createFacePack(@Valid ImFacePackSaveReqVO reqVO); | 60 | Long createFacePack(@Valid ImFacePackSaveReqVO reqVO); |
| 49 | 61 | ||
| 50 | /** | 62 | /** |
| 51 | - * 【管理后台】修改表情包 | 63 | + * 修改表情包 |
| 64 | + * | ||
| 65 | + * @param reqVO 修改请求 | ||
| 52 | */ | 66 | */ |
| 53 | void updateFacePack(@Valid ImFacePackSaveReqVO reqVO); | 67 | void updateFacePack(@Valid ImFacePackSaveReqVO reqVO); |
| 54 | 68 | ||
| 55 | /** | 69 | /** |
| 56 | - * 【管理后台】删除表情包;存在表情时拒绝 | 70 | + * 删除表情包;包下存在表情时拒绝,避免历史 face 消息无法回查归属 |
| 71 | + * | ||
| 72 | + * @param id 表情包编号 | ||
| 57 | */ | 73 | */ |
| 58 | void deleteFacePack(Long id); | 74 | void deleteFacePack(Long id); |
| 59 | 75 | ||
| 60 | /** | 76 | /** |
| 61 | - * 【管理后台】批量删除表情包 | 77 | + * 批量删除表情包;任一包下存在表情时整批拒绝,避免「只删一半」中间态 |
| 78 | + * | ||
| 79 | + * @param ids 表情包编号列表 | ||
| 62 | */ | 80 | */ |
| 63 | void deleteFacePackList(List<Long> ids); | 81 | void deleteFacePackList(List<Long> ids); |
| 64 | 82 |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java
| 1 | package cn.iocoder.yudao.module.im.service.face; | 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 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; | 6 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; |
| 5 | import jakarta.validation.Valid; | 7 | import jakarta.validation.Valid; |
| 6 | 8 | ||
| @@ -15,19 +17,44 @@ public interface ImFaceUserItemService { | @@ -15,19 +17,44 @@ public interface ImFaceUserItemService { | ||
| 15 | 17 | ||
| 16 | /** | 18 | /** |
| 17 | * 获取指定用户的个人表情列表 | 19 | * 获取指定用户的个人表情列表 |
| 20 | + * | ||
| 21 | + * @param userId 用户编号 | ||
| 22 | + * @return 个人表情列表 | ||
| 18 | */ | 23 | */ |
| 19 | List<ImFaceUserItemDO> getFaceUserItemList(Long userId); | 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 | Long createFaceUserItem(Long userId, @Valid ImFaceUserItemSaveReqVO reqVO); | 33 | Long createFaceUserItem(Long userId, @Valid ImFaceUserItemSaveReqVO reqVO); |
| 27 | 34 | ||
| 28 | /** | 35 | /** |
| 29 | * 删除指定用户的某条个人表情 | 36 | * 删除指定用户的某条个人表情 |
| 37 | + * | ||
| 38 | + * @param userId 用户编号 | ||
| 39 | + * @param id 表情编号 | ||
| 30 | */ | 40 | */ |
| 31 | void deleteFaceUserItem(Long userId, Long id); | 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 | package cn.iocoder.yudao.module.im.service.face; | 1 | package cn.iocoder.yudao.module.im.service.face; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.ObjectUtil; | 3 | import cn.hutool.core.util.ObjectUtil; |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 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 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; | 8 | import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; |
| 7 | import cn.iocoder.yudao.module.im.dal.mysql.face.ImFaceUserItemMapper; | 9 | import cn.iocoder.yudao.module.im.dal.mysql.face.ImFaceUserItemMapper; |
| 8 | import jakarta.annotation.Resource; | 10 | import jakarta.annotation.Resource; |
| 9 | -import org.springframework.dao.DuplicateKeyException; | ||
| 10 | import org.springframework.stereotype.Service; | 11 | import org.springframework.stereotype.Service; |
| 11 | import org.springframework.validation.annotation.Validated; | 12 | import org.springframework.validation.annotation.Validated; |
| 12 | 13 | ||
| @@ -41,15 +42,9 @@ public class ImFaceUserItemServiceImpl implements ImFaceUserItemService { | @@ -41,15 +42,9 @@ public class ImFaceUserItemServiceImpl implements ImFaceUserItemService { | ||
| 41 | throw exception(FACE_USER_ITEM_DUPLICATED); | 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 | return item.getId(); | 48 | return item.getId(); |
| 54 | } | 49 | } |
| 55 | 50 | ||
| @@ -69,4 +64,22 @@ public class ImFaceUserItemServiceImpl implements ImFaceUserItemService { | @@ -69,4 +64,22 @@ public class ImFaceUserItemServiceImpl implements ImFaceUserItemService { | ||
| 69 | faceUserItemMapper.deleteById(id); | 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,7 +149,7 @@ CREATE TABLE IF NOT EXISTS "im_group_request" ( | ||
| 149 | CREATE TABLE IF NOT EXISTS "im_face_pack" ( | 149 | CREATE TABLE IF NOT EXISTS "im_face_pack" ( |
| 150 | "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号', | 150 | "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号', |
| 151 | "name" varchar(64) NOT NULL COMMENT '表情包名称', | 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 | "sort" int NOT NULL DEFAULT 0 COMMENT '排序', | 153 | "sort" int NOT NULL DEFAULT 0 COMMENT '排序', |
| 154 | "status" tinyint NOT NULL COMMENT '状态', | 154 | "status" tinyint NOT NULL COMMENT '状态', |
| 155 | "creator" varchar(64) DEFAULT '', | 155 | "creator" varchar(64) DEFAULT '', |
| @@ -186,7 +186,6 @@ CREATE TABLE IF NOT EXISTS "im_face_user_item" ( | @@ -186,7 +186,6 @@ CREATE TABLE IF NOT EXISTS "im_face_user_item" ( | ||
| 186 | "name" varchar(64) DEFAULT NULL COMMENT '表情名(可选)', | 186 | "name" varchar(64) DEFAULT NULL COMMENT '表情名(可选)', |
| 187 | "width" int NOT NULL DEFAULT 0 COMMENT '渲染宽度(像素)', | 187 | "width" int NOT NULL DEFAULT 0 COMMENT '渲染宽度(像素)', |
| 188 | "height" int NOT NULL DEFAULT 0 COMMENT '渲染高度(像素)', | 188 | "height" int NOT NULL DEFAULT 0 COMMENT '渲染高度(像素)', |
| 189 | - "source_message_id" bigint DEFAULT NULL COMMENT '来源消息编号(从消息「添加到表情」时记录;自己上传则为 NULL)', | ||
| 190 | "sort" int NOT NULL DEFAULT 0 COMMENT '排序', | 189 | "sort" int NOT NULL DEFAULT 0 COMMENT '排序', |
| 191 | "creator" varchar(64) DEFAULT '', | 190 | "creator" varchar(64) DEFAULT '', |
| 192 | "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | 191 | "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, |
| @@ -194,6 +193,5 @@ CREATE TABLE IF NOT EXISTS "im_face_user_item" ( | @@ -194,6 +193,5 @@ CREATE TABLE IF NOT EXISTS "im_face_user_item" ( | ||
| 194 | "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | 193 | "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, |
| 195 | "deleted" bit NOT NULL DEFAULT FALSE, | 194 | "deleted" bit NOT NULL DEFAULT FALSE, |
| 196 | "tenant_id" bigint NOT NULL DEFAULT 0, | 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 | ) COMMENT 'IM 用户私有表情表'; | 197 | ) COMMENT 'IM 用户私有表情表'; |