diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFaceUserItemController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFaceUserItemController.java index c070983..7f27c17 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFaceUserItemController.java +++ b/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; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem.ImFaceUserItemRespVO; -import cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem.ImFaceUserItemSaveReqVO; +import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemRespVO; +import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO; import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService; import io.swagger.v3.oas.annotations.Operation; diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/pack/ImFacePackUserRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/pack/ImFacePackUserRespVO.java index 40b2b36..5a73d82 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/pack/ImFacePackUserRespVO.java +++ b/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 { @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") private String name; - @Schema(description = "表情包图标 URL", example = "https://cdn.example.com/face/pack/cat.png") - private String iconUrl; + @Schema(description = "表情包图标", example = "https://cdn.example.com/face/pack/cat.png") + private String icon; @Schema(description = "表情列表", requiredMode = Schema.RequiredMode.REQUIRED) private List items; diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemRespVO.java index b2a4846..61be778 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemRespVO.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem; +package cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemSaveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemSaveReqVO.java index c51eb4b..566c276 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemSaveReqVO.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/userItem/ImFaceUserItemSaveReqVO.java @@ -1,4 +1,5 @@ -package cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem; +// TODO @AI:java 规范,应该是 useritem +package cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; @@ -28,7 +29,4 @@ public class ImFaceUserItemSaveReqVO { @NotNull(message = "渲染高度不能为空") private Integer height; - @Schema(description = "来源消息编号(从消息「添加到表情」时传入;自己上传则不传)", example = "10086") - private Long sourceMessageId; - } diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFaceUserItemManagerController.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFaceUserItemManagerController.java new file mode 100644 index 0000000..df4a06d --- /dev/null +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFaceUserItemManagerController.java @@ -0,0 +1,67 @@ +package cn.iocoder.yudao.module.im.controller.admin.manager.face; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO; +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerRespVO; +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; +import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - IM 用户表情") +@RestController +@RequestMapping("/im/manager/face-user-item") +@Validated +public class ImFaceUserItemManagerController { + + @Resource + private ImFaceUserItemService faceUserItemService; + @Resource + private AdminUserApi adminUserApi; + + @GetMapping("/page") + @Operation(summary = "获得用户表情分页") + @PreAuthorize("@ss.hasPermission('im:manager:face-user-item:query')") + public CommonResult> getFaceUserItemPage( + @Valid ImFaceUserItemManagerPageReqVO pageReqVO) { + PageResult pageResult = faceUserItemService.getFaceUserItemPage(pageReqVO); + // 关联回填用户昵称 + Map userMap = adminUserApi.getUserMap( + CollectionUtils.convertSet(pageResult.getList(), ImFaceUserItemDO::getUserId)); + List voList = CollectionUtils.convertList(pageResult.getList(), item -> { + ImFaceUserItemManagerRespVO vo = BeanUtils.toBean(item, ImFaceUserItemManagerRespVO.class); + AdminUserRespDTO user = userMap.get(item.getUserId()); + if (user != null) { + vo.setUserNickname(user.getNickname()); + } + return vo; + }); + return success(new PageResult<>(voList, pageResult.getTotal())); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除用户表情") + @Parameter(name = "id", description = "编号", required = true, example = "4096") + @PreAuthorize("@ss.hasPermission('im:manager:face-user-item:delete')") + public CommonResult deleteFaceUserItem(@RequestParam("id") Long id) { + faceUserItemService.deleteFaceUserItem(id); + return success(true); + } + +} diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemPageReqVO.java index 6b64242..a2b2a1c 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/item/ImFacePackItemPageReqVO.java +++ b/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; import lombok.Data; import lombok.EqualsAndHashCode; -// TODO @AI:拆分到 vo/item 目录下,如果是 item 的话;更简练; @Schema(description = "管理后台 - IM 表情包项分页 Request VO") @Data @EqualsAndHashCode(callSuper = true) diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackRespVO.java index 142ed65..bdc53d2 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackRespVO.java +++ b/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 { @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") private String name; - @Schema(description = "表情包图标 URL", example = "https://cdn.example.com/face/pack/cat.png") - private String iconUrl; + @Schema(description = "表情包图标", example = "https://cdn.example.com/face/pack/cat.png") + private String icon; @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") private Integer sort; diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackSaveReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackSaveReqVO.java index 01c0358..eaed5e9 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/pack/ImFacePackSaveReqVO.java +++ b/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 { @Size(max = 64, message = "表情包名称长度不能超过 64") private String name; - @Schema(description = "表情包图标 URL", example = "https://cdn.example.com/face/pack/cat.png") - @Size(max = 512, message = "图标 URL 长度不能超过 512") - private String iconUrl; + @Schema(description = "表情包图标", example = "https://cdn.example.com/face/pack/cat.png") + @Size(max = 512, message = "图标长度不能超过 512") + private String icon; @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @NotNull(message = "排序不能为空") diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerPageReqVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerPageReqVO.java new file mode 100644 index 0000000..dec8f1f --- /dev/null +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerPageReqVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - IM 用户表情分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +public class ImFaceUserItemManagerPageReqVO extends PageParam { + + @Schema(description = "所属用户编号", example = "1024") + private Long userId; + + @Schema(description = "表情名,模糊匹配", example = "狗") + private String name; + + @Schema(description = "添加时间", example = "[2026-04-01 00:00:00, 2026-04-30 23:59:59]") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerRespVO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerRespVO.java new file mode 100644 index 0000000..723fc48 --- /dev/null +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/useritem/ImFaceUserItemManagerRespVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - IM 用户表情 Response VO") +@Data +public class ImFaceUserItemManagerRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") + private Long id; + + @Schema(description = "所属用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long userId; + + @Schema(description = "所属用户昵称", example = "张三") + private String userNickname; + + @Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED, + example = "https://cdn.example.com/face/user/abc.gif") + private String url; + + @Schema(description = "表情名", example = "狗头") + private String name; + + @Schema(description = "渲染宽度(像素)", example = "200") + private Integer width; + + @Schema(description = "渲染高度(像素)", example = "200") + private Integer height; + + @Schema(description = "添加时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackDO.java index 5722e10..0236218 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackDO.java +++ b/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 { * 表情包名称 */ private String name; - // TODO @AI:icon 一般不带 url;类似 avatar,特有单词; /** - * 表情包图标 URL + * 表情包图标 *

* 面板底部 tab 栏显示 */ - private String iconUrl; + private String icon; /** * 排序 */ diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFaceUserItemDO.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFaceUserItemDO.java index 8ddd826..0aee3bb 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFaceUserItemDO.java +++ b/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 { private Long id; /** * 所属用户编号 - * - * // TODO @AI:是不是要关联下 userid + *

+ * 关联 AdminUserDO 的 id 编号 */ private Long userId; /** @@ -51,14 +51,6 @@ public class ImFaceUserItemDO extends BaseDO { */ private Integer height; /** - * 来源消息编号 - *

- * 从消息「添加到表情」时记录;自己上传则为 NULL;用于排查 / 后续溯源 - * - * TODO @AI:关联字段; - */ - private Long sourceMessageId; - /** * 排序 */ private Integer sort; diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java index 6445af0..4518d94 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.im.dal.mysql.face; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO; import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; import org.apache.ibatis.annotations.Mapper; @@ -15,7 +17,6 @@ import java.util.List; @Mapper public interface ImFaceUserItemMapper extends BaseMapperX { - /** 取用户的所有个人表情,按 sort 升序、id 倒序(最近添加在前) */ default List selectListByUserId(Long userId) { return selectList(new LambdaQueryWrapperX() .eq(ImFaceUserItemDO::getUserId, userId) @@ -23,15 +24,18 @@ public interface ImFaceUserItemMapper extends BaseMapperX { .orderByDesc(ImFaceUserItemDO::getId)); } - default Long selectCountByUserId(Long userId) { - return selectCount(new LambdaQueryWrapperX() - .eq(ImFaceUserItemDO::getUserId, userId)); - } - default ImFaceUserItemDO selectByUserIdAndUrl(Long userId, String url) { return selectOne(new LambdaQueryWrapperX() .eq(ImFaceUserItemDO::getUserId, userId) .eq(ImFaceUserItemDO::getUrl, url)); } + default PageResult selectPage(ImFaceUserItemManagerPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ImFaceUserItemDO::getUserId, reqVO.getUserId()) + .likeIfPresent(ImFaceUserItemDO::getName, reqVO.getName()) + .betweenIfPresent(ImFaceUserItemDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ImFaceUserItemDO::getId)); + } + } diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java index 7ae94f6..c9f913e 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java @@ -9,8 +9,6 @@ import jakarta.validation.Valid; import java.util.Collection; import java.util.List; -// TODO @AI:已经分了用户端、和管理后台,注释上就不用写【用户端】【【管理后台】】了。。。 -// TODO @AI:注释的风格,参考下别的模块,一些 params、return 都要写呀; /** * IM 表情包项 Service 接口 * @@ -21,49 +19,73 @@ public interface ImFacePackItemService { // ==================== 用户端 ==================== /** - * 【用户端】按 packIds 批量取启用项,给前端聚合接口用 + * 按 packIds 批量取启用项,给前端聚合接口用 + * + * @param packIds 表情包编号列表 + * @return 启用状态的表情列表 */ List getEnabledItemListByPackIds(Collection packIds); /** * 取某个表情包下的表情数量;ImFacePackService 删除前校验「包下无项」用 + * + * @param packId 表情包编号 + * @return 数量 */ Long getFacePackItemCount(Long packId); /** * 取多个表情包下的表情数量合计;ImFacePackService 批量删除前校验用 + * + * @param packIds 表情包编号列表 + * @return 数量合计 */ Long getFacePackItemCount(Collection packIds); // ==================== 管理后台 ==================== /** - * 【管理后台】分页查询 + * 分页查询表情包项 + * + * @param reqVO 分页查询条件 + * @return 表情包项分页 */ PageResult getFacePackItemPage(ImFacePackItemPageReqVO reqVO); /** - * 【管理后台】获取详情 + * 获取表情包项详情 + * + * @param id 表情包项编号 + * @return 表情包项 DO */ ImFacePackItemDO getFacePackItem(Long id); /** - * 【管理后台】新增,返回新增 id + * 新增表情包项 + * + * @param reqVO 新增请求 + * @return 新增表情包项编号 */ Long createFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); /** - * 【管理后台】修改 + * 修改表情包项 + * + * @param reqVO 修改请求 */ void updateFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); /** - * 【管理后台】删除 + * 删除表情包项 + * + * @param id 表情包项编号 */ void deleteFacePackItem(Long id); /** - * 【管理后台】批量删除 + * 批量删除表情包项 + * + * @param ids 表情包项编号列表 */ void deleteFacePackItemList(List ids); diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java index a05596b..d579fbf 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java @@ -15,17 +15,20 @@ import java.util.List; */ public interface ImFacePackService { - // TODO @AI:已经区分了 === 就不用写【用户端】【管理后台】了。 - // ==================== 用户端 ==================== /** - * 【用户端】获取所有启用的表情包,按 sort 升序 + * 获取所有启用的表情包,按 sort 升序 + * + * @return 启用的表情包列表 */ List getEnabledFacePackList(); /** * 校验表情包存在 + * + * @param id 表情包编号 + * @return 表情包 DO */ @SuppressWarnings("UnusedReturnValue") ImFacePackDO validateFacePackExists(Long id); @@ -33,32 +36,47 @@ public interface ImFacePackService { // ==================== 管理后台 ==================== /** - * 【管理后台】分页查询表情包 + * 分页查询表情包 + * + * @param reqVO 分页查询条件 + * @return 表情包分页 */ PageResult getFacePackPage(ImFacePackPageReqVO reqVO); /** - * 【管理后台】获取表情包详情 + * 获取表情包详情 + * + * @param id 表情包编号 + * @return 表情包 DO */ ImFacePackDO getFacePack(Long id); /** - * 【管理后台】新增表情包,返回新增 id + * 新增表情包 + * + * @param reqVO 新增请求 + * @return 新增表情包编号 */ Long createFacePack(@Valid ImFacePackSaveReqVO reqVO); /** - * 【管理后台】修改表情包 + * 修改表情包 + * + * @param reqVO 修改请求 */ void updateFacePack(@Valid ImFacePackSaveReqVO reqVO); /** - * 【管理后台】删除表情包;存在表情时拒绝 + * 删除表情包;包下存在表情时拒绝,避免历史 face 消息无法回查归属 + * + * @param id 表情包编号 */ void deleteFacePack(Long id); /** - * 【管理后台】批量删除表情包 + * 批量删除表情包;任一包下存在表情时整批拒绝,避免「只删一半」中间态 + * + * @param ids 表情包编号列表 */ void deleteFacePackList(List ids); diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java index a421024..68ae78c 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.im.service.face; -import cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem.ImFaceUserItemSaveReqVO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO; +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO; import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; import jakarta.validation.Valid; @@ -15,19 +17,44 @@ public interface ImFaceUserItemService { /** * 获取指定用户的个人表情列表 + * + * @param userId 用户编号 + * @return 个人表情列表 */ List getFaceUserItemList(Long userId); /** - * 添加个人表情;返回新增记录 id - *

- * 同 URL 重复添加抛 FACE_USER_ITEM_DUPLICATED;表上 (user_id, url) 唯一约束兜底并发 race + * 添加个人表情 + * + * @param userId 用户编号 + * @param reqVO 添加请求 + * @return 新增表情编号 */ Long createFaceUserItem(Long userId, @Valid ImFaceUserItemSaveReqVO reqVO); /** * 删除指定用户的某条个人表情 + * + * @param userId 用户编号 + * @param id 表情编号 */ void deleteFaceUserItem(Long userId, Long id); + // ==================== 管理后台 ==================== + + /** + * 分页查询所有用户的个人表情;管理后台审计 / 删除违规图用 + * + * @param reqVO 分页查询条件 + * @return 个人表情分页 + */ + PageResult getFaceUserItemPage(ImFaceUserItemManagerPageReqVO reqVO); + + /** + * 管理后台直接删除某条个人表情;不做归属校验 + * + * @param id 表情编号 + */ + void deleteFaceUserItem(Long id); + } diff --git a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java index 853dd22..556cf5d 100644 --- a/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java +++ b/yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java @@ -1,12 +1,13 @@ package cn.iocoder.yudao.module.im.service.face; import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.im.controller.admin.face.vo.userItem.ImFaceUserItemSaveReqVO; +import cn.iocoder.yudao.module.im.controller.admin.face.vo.useritem.ImFaceUserItemSaveReqVO; +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.useritem.ImFaceUserItemManagerPageReqVO; import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; import cn.iocoder.yudao.module.im.dal.mysql.face.ImFaceUserItemMapper; import jakarta.annotation.Resource; -import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -41,15 +42,9 @@ public class ImFaceUserItemServiceImpl implements ImFaceUserItemService { throw exception(FACE_USER_ITEM_DUPLICATED); } - // 2. 入库;表 (user_id, url, tenant_id) 唯一约束兜底并发 race —— 两个请求同时过 step 1 时 DB 拦截 - // TODO @AI:不加唯一索引。不然删除后恢复麻烦。按照我说的来。 - ImFaceUserItemDO item = BeanUtils.toBean(reqVO, ImFaceUserItemDO.class) - .setUserId(userId); - try { - faceUserItemMapper.insert(item); - } catch (DuplicateKeyException ignored) { - throw exception(FACE_USER_ITEM_DUPLICATED); - } + // 2. 入库 + ImFaceUserItemDO item = BeanUtils.toBean(reqVO, ImFaceUserItemDO.class).setUserId(userId); + faceUserItemMapper.insert(item); return item.getId(); } @@ -69,4 +64,22 @@ public class ImFaceUserItemServiceImpl implements ImFaceUserItemService { faceUserItemMapper.deleteById(id); } + // ==================== 管理后台 ==================== + + @Override + public PageResult getFaceUserItemPage(ImFaceUserItemManagerPageReqVO reqVO) { + return faceUserItemMapper.selectPage(reqVO); + } + + @Override + public void deleteFaceUserItem(Long id) { + // 1. 校验存在 + if (faceUserItemMapper.selectById(id) == null) { + throw exception(FACE_USER_ITEM_NOT_EXISTS); + } + + // 2. 删除 + faceUserItemMapper.deleteById(id); + } + } diff --git a/yudao-module-im/src/test/resources/sql/create_tables.sql b/yudao-module-im/src/test/resources/sql/create_tables.sql index d12e0f4..a62b4cf 100644 --- a/yudao-module-im/src/test/resources/sql/create_tables.sql +++ b/yudao-module-im/src/test/resources/sql/create_tables.sql @@ -149,7 +149,7 @@ CREATE TABLE IF NOT EXISTS "im_group_request" ( CREATE TABLE IF NOT EXISTS "im_face_pack" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY COMMENT '编号', "name" varchar(64) NOT NULL COMMENT '表情包名称', - "icon_url" varchar(512) DEFAULT NULL COMMENT '表情包图标 URL(面板底部 tab 显示)', + "icon" varchar(512) DEFAULT NULL COMMENT '表情包图标(面板底部 tab 显示)', "sort" int NOT NULL DEFAULT 0 COMMENT '排序', "status" tinyint NOT NULL COMMENT '状态', "creator" varchar(64) DEFAULT '', @@ -186,7 +186,6 @@ CREATE TABLE IF NOT EXISTS "im_face_user_item" ( "name" varchar(64) DEFAULT NULL COMMENT '表情名(可选)', "width" int NOT NULL DEFAULT 0 COMMENT '渲染宽度(像素)', "height" int NOT NULL DEFAULT 0 COMMENT '渲染高度(像素)', - "source_message_id" bigint DEFAULT NULL COMMENT '来源消息编号(从消息「添加到表情」时记录;自己上传则为 NULL)', "sort" int NOT NULL DEFAULT 0 COMMENT '排序', "creator" varchar(64) DEFAULT '', "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, @@ -194,6 +193,5 @@ CREATE TABLE IF NOT EXISTS "im_face_user_item" ( "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, "deleted" bit NOT NULL DEFAULT FALSE, "tenant_id" bigint NOT NULL DEFAULT 0, - PRIMARY KEY ("id"), - CONSTRAINT "uk_im_face_user_item_user_url" UNIQUE ("user_id", "url", "tenant_id") + PRIMARY KEY ("id") ) COMMENT 'IM 用户私有表情表';