Commit 8a4ad959d6e67755f424d858246cf6c1ffb1294c
1 parent
b320e3c1
✨ feat(im): 初始化表情包 v0.0:第一把 review
Showing
27 changed files
with
1415 additions
and
7 deletions
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFacePackController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 5 | +import cn.iocoder.yudao.module.im.controller.admin.face.vo.ImFacePackUserRespVO; | ||
| 6 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO; | ||
| 7 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO; | ||
| 8 | +import cn.iocoder.yudao.module.im.service.face.ImFacePackItemService; | ||
| 9 | +import cn.iocoder.yudao.module.im.service.face.ImFacePackService; | ||
| 10 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 11 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 12 | +import jakarta.annotation.Resource; | ||
| 13 | +import org.springframework.validation.annotation.Validated; | ||
| 14 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 15 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 16 | +import org.springframework.web.bind.annotation.RestController; | ||
| 17 | + | ||
| 18 | +import java.util.List; | ||
| 19 | +import java.util.Map; | ||
| 20 | + | ||
| 21 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 22 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 23 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; | ||
| 24 | + | ||
| 25 | +@Tag(name = "管理后台 - IM 表情包") | ||
| 26 | +@RestController | ||
| 27 | +@RequestMapping("/im/face-pack") | ||
| 28 | +@Validated | ||
| 29 | +public class ImFacePackController { | ||
| 30 | + | ||
| 31 | + @Resource | ||
| 32 | + private ImFacePackService facePackService; | ||
| 33 | + @Resource | ||
| 34 | + private ImFacePackItemService facePackItemService; | ||
| 35 | + | ||
| 36 | + @GetMapping("/list") | ||
| 37 | + @Operation(summary = "获得启用的表情包列表(含表情)") | ||
| 38 | + public CommonResult<List<ImFacePackUserRespVO>> getFacePackList() { | ||
| 39 | + // 1.1 拉所有启用表情包 | ||
| 40 | + List<ImFacePackDO> packs = facePackService.getEnabledFacePackList(); | ||
| 41 | + if (packs.isEmpty()) { | ||
| 42 | + return success(List.of()); | ||
| 43 | + } | ||
| 44 | + // 1.2 拉这些包下所有启用表情,按 packId 分组 | ||
| 45 | + List<ImFacePackItemDO> items = facePackItemService.getEnabledItemListByPackIds( | ||
| 46 | + convertList(packs, ImFacePackDO::getId)); | ||
| 47 | + Map<Long, List<ImFacePackItemDO>> itemsByPackId = convertMultiMap(items, ImFacePackItemDO::getPackId); | ||
| 48 | + | ||
| 49 | + // 2. 拼装:BeanUtils 把 pack 字段映射 + 自己塞 items | ||
| 50 | + List<ImFacePackUserRespVO> result = convertList(packs, pack -> { | ||
| 51 | + ImFacePackUserRespVO vo = BeanUtils.toBean(pack, ImFacePackUserRespVO.class); | ||
| 52 | + vo.setItems(BeanUtils.toBean(itemsByPackId.getOrDefault(pack.getId(), List.of()), ImFacePackUserRespVO.Item.class)); | ||
| 53 | + return vo; | ||
| 54 | + }); | ||
| 55 | + return success(result); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/ImFaceUserItemController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 5 | +import cn.iocoder.yudao.module.im.controller.admin.face.vo.ImFaceUserItemRespVO; | ||
| 6 | +import cn.iocoder.yudao.module.im.controller.admin.face.vo.ImFaceUserItemSaveReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; | ||
| 8 | +import cn.iocoder.yudao.module.im.service.face.ImFaceUserItemService; | ||
| 9 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 10 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 11 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 12 | +import jakarta.annotation.Resource; | ||
| 13 | +import jakarta.validation.Valid; | ||
| 14 | +import org.springframework.validation.annotation.Validated; | ||
| 15 | +import org.springframework.web.bind.annotation.*; | ||
| 16 | + | ||
| 17 | +import java.util.List; | ||
| 18 | + | ||
| 19 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 20 | +import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; | ||
| 21 | + | ||
| 22 | +@Tag(name = "管理后台 - IM 个人表情") | ||
| 23 | +@RestController | ||
| 24 | +@RequestMapping("/im/face-user-item") | ||
| 25 | +@Validated | ||
| 26 | +public class ImFaceUserItemController { | ||
| 27 | + | ||
| 28 | + @Resource | ||
| 29 | + private ImFaceUserItemService faceUserItemService; | ||
| 30 | + | ||
| 31 | + @GetMapping("/list") | ||
| 32 | + @Operation(summary = "获得我的个人表情列表") | ||
| 33 | + public CommonResult<List<ImFaceUserItemRespVO>> getMyFaceUserItemList() { | ||
| 34 | + List<ImFaceUserItemDO> items = faceUserItemService.getMyFaceUserItemList(getLoginUserId()); | ||
| 35 | + return success(BeanUtils.toBean(items, ImFaceUserItemRespVO.class)); | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + @PostMapping("/create") | ||
| 39 | + @Operation(summary = "添加个人表情") | ||
| 40 | + public CommonResult<Long> createFaceUserItem(@Valid @RequestBody ImFaceUserItemSaveReqVO reqVO) { | ||
| 41 | + return success(faceUserItemService.createFaceUserItem(getLoginUserId(), reqVO)); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + @DeleteMapping("/delete") | ||
| 45 | + @Operation(summary = "删除个人表情") | ||
| 46 | + @Parameter(name = "id", description = "编号", required = true, example = "4096") | ||
| 47 | + public CommonResult<Boolean> deleteFaceUserItem(@RequestParam("id") Long id) { | ||
| 48 | + faceUserItemService.deleteFaceUserItem(getLoginUserId(), id); | ||
| 49 | + return success(true); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + // TODO @AI:个人应该没批量删除把?应该就一个一个删除呢。 | ||
| 53 | + @DeleteMapping("/delete-list") | ||
| 54 | + @Operation(summary = "批量删除个人表情") | ||
| 55 | + @Parameter(name = "ids", description = "编号列表", required = true) | ||
| 56 | + public CommonResult<Boolean> deleteFaceUserItemList(@RequestParam("ids") List<Long> ids) { | ||
| 57 | + faceUserItemService.deleteFaceUserItemList(getLoginUserId(), ids); | ||
| 58 | + return success(true); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/ImFacePackUserRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.face.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.util.List; | ||
| 7 | + | ||
| 8 | +@Schema(description = "IM 表情包(用户端) Response VO") | ||
| 9 | +@Data | ||
| 10 | +public class ImFacePackUserRespVO { | ||
| 11 | + | ||
| 12 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 13 | + private Long id; | ||
| 14 | + | ||
| 15 | + @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") | ||
| 16 | + private String name; | ||
| 17 | + | ||
| 18 | + @Schema(description = "表情包图标 URL", example = "https://cdn.example.com/face/pack/cat.png") | ||
| 19 | + private String iconUrl; | ||
| 20 | + | ||
| 21 | + @Schema(description = "表情列表", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 22 | + private List<Item> items; | ||
| 23 | + | ||
| 24 | + @Schema(description = "IM 表情包项(用户端)") | ||
| 25 | + @Data | ||
| 26 | + public static class Item { | ||
| 27 | + | ||
| 28 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") | ||
| 29 | + private Long id; | ||
| 30 | + | ||
| 31 | + @Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED, | ||
| 32 | + example = "https://cdn.example.com/face/pack/cat-001.png") | ||
| 33 | + private String url; | ||
| 34 | + | ||
| 35 | + @Schema(description = "表情名", example = "狗头") | ||
| 36 | + private String name; | ||
| 37 | + | ||
| 38 | + @Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 39 | + private Integer width; | ||
| 40 | + | ||
| 41 | + @Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 42 | + private Integer height; | ||
| 43 | + | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/ImFaceUserItemRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.face.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +@Schema(description = "IM 个人表情 Response VO") | ||
| 7 | +@Data | ||
| 8 | +public class ImFaceUserItemRespVO { | ||
| 9 | + | ||
| 10 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") | ||
| 11 | + private Long id; | ||
| 12 | + | ||
| 13 | + @Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED, | ||
| 14 | + example = "https://cdn.example.com/face/user/abc.gif") | ||
| 15 | + private String url; | ||
| 16 | + | ||
| 17 | + @Schema(description = "表情名", example = "狗头") | ||
| 18 | + private String name; | ||
| 19 | + | ||
| 20 | + @Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 21 | + private Integer width; | ||
| 22 | + | ||
| 23 | + @Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 24 | + private Integer height; | ||
| 25 | + | ||
| 26 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/face/vo/ImFaceUserItemSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.face.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import jakarta.validation.constraints.NotBlank; | ||
| 5 | +import jakarta.validation.constraints.NotNull; | ||
| 6 | +import jakarta.validation.constraints.Size; | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +@Schema(description = "IM 个人表情新增 Request VO") | ||
| 10 | +@Data | ||
| 11 | +public class ImFaceUserItemSaveReqVO { | ||
| 12 | + | ||
| 13 | + @Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED, | ||
| 14 | + example = "https://cdn.example.com/face/user/abc.gif") | ||
| 15 | + @NotBlank(message = "表情图 URL 不能为空") | ||
| 16 | + @Size(max = 512, message = "表情图 URL 长度不能超过 512") | ||
| 17 | + private String url; | ||
| 18 | + | ||
| 19 | + @Schema(description = "表情名", example = "狗头") | ||
| 20 | + @Size(max = 64, message = "表情名长度不能超过 64") | ||
| 21 | + private String name; | ||
| 22 | + | ||
| 23 | + @Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 24 | + @NotNull(message = "渲染宽度不能为空") | ||
| 25 | + private Integer width; | ||
| 26 | + | ||
| 27 | + @Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 28 | + @NotNull(message = "渲染高度不能为空") | ||
| 29 | + private Integer height; | ||
| 30 | + | ||
| 31 | + @Schema(description = "来源消息编号(从消息「添加到表情」时传入;自己上传则不传)", example = "10086") | ||
| 32 | + private Long sourceMessageId; | ||
| 33 | + | ||
| 34 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackItemManagerController.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.object.BeanUtils; | ||
| 6 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackItemPageReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackItemRespVO; | ||
| 8 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackItemSaveReqVO; | ||
| 9 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO; | ||
| 10 | +import cn.iocoder.yudao.module.im.service.face.ImFacePackItemService; | ||
| 11 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 12 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 13 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 14 | +import jakarta.annotation.Resource; | ||
| 15 | +import jakarta.validation.Valid; | ||
| 16 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 17 | +import org.springframework.validation.annotation.Validated; | ||
| 18 | +import org.springframework.web.bind.annotation.*; | ||
| 19 | + | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 23 | + | ||
| 24 | +@Tag(name = "管理后台 - IM 表情包项") | ||
| 25 | +@RestController | ||
| 26 | +@RequestMapping("/im/manager/face-pack-item") | ||
| 27 | +@Validated | ||
| 28 | +public class ImFacePackItemManagerController { | ||
| 29 | + | ||
| 30 | + @Resource | ||
| 31 | + private ImFacePackItemService facePackItemService; | ||
| 32 | + | ||
| 33 | + @PostMapping("/create") | ||
| 34 | + @Operation(summary = "新增表情") | ||
| 35 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:create')") | ||
| 36 | + public CommonResult<Long> createFacePackItem(@Valid @RequestBody ImFacePackItemSaveReqVO reqVO) { | ||
| 37 | + return success(facePackItemService.createFacePackItem(reqVO)); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + @PutMapping("/update") | ||
| 41 | + @Operation(summary = "修改表情") | ||
| 42 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:update')") | ||
| 43 | + public CommonResult<Boolean> updateFacePackItem(@Valid @RequestBody ImFacePackItemSaveReqVO reqVO) { | ||
| 44 | + facePackItemService.updateFacePackItem(reqVO); | ||
| 45 | + return success(true); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + @DeleteMapping("/delete") | ||
| 49 | + @Operation(summary = "删除表情") | ||
| 50 | + @Parameter(name = "id", description = "编号", required = true, example = "2048") | ||
| 51 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:delete')") | ||
| 52 | + public CommonResult<Boolean> deleteFacePackItem(@RequestParam("id") Long id) { | ||
| 53 | + facePackItemService.deleteFacePackItem(id); | ||
| 54 | + return success(true); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @DeleteMapping("/delete-list") | ||
| 58 | + @Operation(summary = "批量删除表情") | ||
| 59 | + @Parameter(name = "ids", description = "编号列表", required = true) | ||
| 60 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:delete')") | ||
| 61 | + public CommonResult<Boolean> deleteFacePackItemList(@RequestParam("ids") List<Long> ids) { | ||
| 62 | + facePackItemService.deleteFacePackItemList(ids); | ||
| 63 | + return success(true); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + @GetMapping("/page") | ||
| 67 | + @Operation(summary = "获得表情分页") | ||
| 68 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:query')") | ||
| 69 | + public CommonResult<PageResult<ImFacePackItemRespVO>> getFacePackItemPage(@Valid ImFacePackItemPageReqVO pageReqVO) { | ||
| 70 | + PageResult<ImFacePackItemDO> pageResult = facePackItemService.getFacePackItemPage(pageReqVO); | ||
| 71 | + return success(BeanUtils.toBean(pageResult, ImFacePackItemRespVO.class)); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + @GetMapping("/get") | ||
| 75 | + @Operation(summary = "获得表情详情") | ||
| 76 | + @Parameter(name = "id", description = "编号", required = true, example = "2048") | ||
| 77 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack-item:query')") | ||
| 78 | + public CommonResult<ImFacePackItemRespVO> getFacePackItem(@RequestParam("id") Long id) { | ||
| 79 | + ImFacePackItemDO item = facePackItemService.getFacePackItem(id); | ||
| 80 | + return success(BeanUtils.toBean(item, ImFacePackItemRespVO.class)); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/ImFacePackManagerController.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.object.BeanUtils; | ||
| 6 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackPageReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackRespVO; | ||
| 8 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackSaveReqVO; | ||
| 9 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO; | ||
| 10 | +import cn.iocoder.yudao.module.im.service.face.ImFacePackService; | ||
| 11 | +import io.swagger.v3.oas.annotations.Operation; | ||
| 12 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 13 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 14 | +import jakarta.annotation.Resource; | ||
| 15 | +import jakarta.validation.Valid; | ||
| 16 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 17 | +import org.springframework.validation.annotation.Validated; | ||
| 18 | +import org.springframework.web.bind.annotation.*; | ||
| 19 | + | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 23 | + | ||
| 24 | +@Tag(name = "管理后台 - IM 表情包") | ||
| 25 | +@RestController | ||
| 26 | +@RequestMapping("/im/manager/face-pack") | ||
| 27 | +@Validated | ||
| 28 | +public class ImFacePackManagerController { | ||
| 29 | + | ||
| 30 | + @Resource | ||
| 31 | + private ImFacePackService facePackService; | ||
| 32 | + | ||
| 33 | + @PostMapping("/create") | ||
| 34 | + @Operation(summary = "新增表情包") | ||
| 35 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack:create')") | ||
| 36 | + public CommonResult<Long> createFacePack(@Valid @RequestBody ImFacePackSaveReqVO reqVO) { | ||
| 37 | + return success(facePackService.createFacePack(reqVO)); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + @PutMapping("/update") | ||
| 41 | + @Operation(summary = "修改表情包") | ||
| 42 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack:update')") | ||
| 43 | + public CommonResult<Boolean> updateFacePack(@Valid @RequestBody ImFacePackSaveReqVO reqVO) { | ||
| 44 | + facePackService.updateFacePack(reqVO); | ||
| 45 | + return success(true); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + @DeleteMapping("/delete") | ||
| 49 | + @Operation(summary = "删除表情包") | ||
| 50 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||
| 51 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack:delete')") | ||
| 52 | + public CommonResult<Boolean> deleteFacePack(@RequestParam("id") Long id) { | ||
| 53 | + facePackService.deleteFacePack(id); | ||
| 54 | + return success(true); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @DeleteMapping("/delete-list") | ||
| 58 | + @Operation(summary = "批量删除表情包") | ||
| 59 | + @Parameter(name = "ids", description = "编号列表", required = true) | ||
| 60 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack:delete')") | ||
| 61 | + public CommonResult<Boolean> deleteFacePackList(@RequestParam("ids") List<Long> ids) { | ||
| 62 | + facePackService.deleteFacePackList(ids); | ||
| 63 | + return success(true); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + @GetMapping("/page") | ||
| 67 | + @Operation(summary = "获得表情包分页") | ||
| 68 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack:query')") | ||
| 69 | + public CommonResult<PageResult<ImFacePackRespVO>> getFacePackPage(@Valid ImFacePackPageReqVO pageReqVO) { | ||
| 70 | + PageResult<ImFacePackDO> pageResult = facePackService.getFacePackPage(pageReqVO); | ||
| 71 | + return success(BeanUtils.toBean(pageResult, ImFacePackRespVO.class)); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + @GetMapping("/get") | ||
| 75 | + @Operation(summary = "获得表情包详情") | ||
| 76 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | ||
| 77 | + @PreAuthorize("@ss.hasPermission('im:manager:face-pack:query')") | ||
| 78 | + public CommonResult<ImFacePackRespVO> getFacePack(@RequestParam("id") Long id) { | ||
| 79 | + ImFacePackDO pack = facePackService.getFacePack(id); | ||
| 80 | + return success(BeanUtils.toBean(pack, ImFacePackRespVO.class)); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/ImFacePackItemPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo; | ||
| 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 | + | ||
| 8 | +// TODO @AI:拆分到 vo/item 目录下,如果是 item 的话;更简练; | ||
| 9 | +@Schema(description = "管理后台 - IM 表情包项分页 Request VO") | ||
| 10 | +@Data | ||
| 11 | +@EqualsAndHashCode(callSuper = true) | ||
| 12 | +public class ImFacePackItemPageReqVO extends PageParam { | ||
| 13 | + | ||
| 14 | + @Schema(description = "所属表情包编号", example = "1024") | ||
| 15 | + private Long packId; | ||
| 16 | + | ||
| 17 | + @Schema(description = "表情名,模糊匹配", example = "狗") | ||
| 18 | + private String name; | ||
| 19 | + | ||
| 20 | + @Schema(description = "状态", example = "0") | ||
| 21 | + private Integer status; // 参见 CommonStatusEnum 枚举类 | ||
| 22 | + | ||
| 23 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/ImFacePackItemRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo; | ||
| 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 ImFacePackItemRespVO { | ||
| 11 | + | ||
| 12 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") | ||
| 13 | + private Long id; | ||
| 14 | + | ||
| 15 | + @Schema(description = "所属表情包编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 16 | + private Long packId; | ||
| 17 | + | ||
| 18 | + @Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED, | ||
| 19 | + example = "https://cdn.example.com/face/pack/cat-001.png") | ||
| 20 | + private String url; | ||
| 21 | + | ||
| 22 | + @Schema(description = "表情名", example = "狗头") | ||
| 23 | + private String name; | ||
| 24 | + | ||
| 25 | + @Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 26 | + private Integer width; | ||
| 27 | + | ||
| 28 | + @Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 29 | + private Integer height; | ||
| 30 | + | ||
| 31 | + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 32 | + private Integer sort; | ||
| 33 | + | ||
| 34 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 35 | + private Integer status; // 参见 CommonStatusEnum 枚举类 | ||
| 36 | + | ||
| 37 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 38 | + private LocalDateTime createTime; | ||
| 39 | + | ||
| 40 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/ImFacePackItemSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import jakarta.validation.constraints.NotBlank; | ||
| 5 | +import jakarta.validation.constraints.NotNull; | ||
| 6 | +import jakarta.validation.constraints.Size; | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +@Schema(description = "管理后台 - IM 表情包项新增 / 修改 Request VO") | ||
| 10 | +@Data | ||
| 11 | +public class ImFacePackItemSaveReqVO { | ||
| 12 | + | ||
| 13 | + @Schema(description = "编号(修改时必填)", example = "2048") | ||
| 14 | + private Long id; | ||
| 15 | + | ||
| 16 | + @Schema(description = "所属表情包编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 17 | + @NotNull(message = "表情包编号不能为空") | ||
| 18 | + private Long packId; | ||
| 19 | + | ||
| 20 | + @Schema(description = "表情图 URL", requiredMode = Schema.RequiredMode.REQUIRED, | ||
| 21 | + example = "https://cdn.example.com/face/pack/cat-001.png") | ||
| 22 | + @NotBlank(message = "表情图 URL 不能为空") | ||
| 23 | + @Size(max = 512, message = "表情图 URL 长度不能超过 512") | ||
| 24 | + private String url; | ||
| 25 | + | ||
| 26 | + @Schema(description = "表情名", example = "狗头") | ||
| 27 | + @Size(max = 64, message = "表情名长度不能超过 64") | ||
| 28 | + private String name; | ||
| 29 | + | ||
| 30 | + @Schema(description = "渲染宽度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 31 | + @NotNull(message = "渲染宽度不能为空") | ||
| 32 | + private Integer width; | ||
| 33 | + | ||
| 34 | + @Schema(description = "渲染高度(像素)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200") | ||
| 35 | + @NotNull(message = "渲染高度不能为空") | ||
| 36 | + private Integer height; | ||
| 37 | + | ||
| 38 | + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 39 | + @NotNull(message = "排序不能为空") | ||
| 40 | + private Integer sort; | ||
| 41 | + | ||
| 42 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 43 | + @NotNull(message = "状态不能为空") | ||
| 44 | + private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) | ||
| 45 | + | ||
| 46 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/ImFacePackPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo; | ||
| 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 ImFacePackPageReqVO extends PageParam { | ||
| 17 | + | ||
| 18 | + @Schema(description = "表情包名称,模糊匹配", example = "猫") | ||
| 19 | + private String name; | ||
| 20 | + | ||
| 21 | + @Schema(description = "状态", example = "0") | ||
| 22 | + private Integer status; // 参见 CommonStatusEnum 枚举类 | ||
| 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/ImFacePackRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo; | ||
| 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 ImFacePackRespVO { | ||
| 11 | + | ||
| 12 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | ||
| 13 | + private Long id; | ||
| 14 | + | ||
| 15 | + @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") | ||
| 16 | + private String name; | ||
| 17 | + | ||
| 18 | + @Schema(description = "表情包图标 URL", example = "https://cdn.example.com/face/pack/cat.png") | ||
| 19 | + private String iconUrl; | ||
| 20 | + | ||
| 21 | + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 22 | + private Integer sort; | ||
| 23 | + | ||
| 24 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 25 | + private Integer status; // 参见 CommonStatusEnum 枚举类 | ||
| 26 | + | ||
| 27 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 28 | + private LocalDateTime createTime; | ||
| 29 | + | ||
| 30 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/manager/face/vo/ImFacePackSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.controller.admin.manager.face.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import jakarta.validation.constraints.NotBlank; | ||
| 5 | +import jakarta.validation.constraints.NotNull; | ||
| 6 | +import jakarta.validation.constraints.Size; | ||
| 7 | +import lombok.Data; | ||
| 8 | + | ||
| 9 | +@Schema(description = "管理后台 - IM 表情包新增 / 修改 Request VO") | ||
| 10 | +@Data | ||
| 11 | +public class ImFacePackSaveReqVO { | ||
| 12 | + | ||
| 13 | + @Schema(description = "编号(修改时必填)", example = "1024") | ||
| 14 | + private Long id; | ||
| 15 | + | ||
| 16 | + @Schema(description = "表情包名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "猫主子") | ||
| 17 | + @NotBlank(message = "表情包名称不能为空") | ||
| 18 | + @Size(max = 64, message = "表情包名称长度不能超过 64") | ||
| 19 | + private String name; | ||
| 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; | ||
| 24 | + | ||
| 25 | + @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 26 | + @NotNull(message = "排序不能为空") | ||
| 27 | + private Integer sort; | ||
| 28 | + | ||
| 29 | + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | ||
| 30 | + @NotNull(message = "状态不能为空") | ||
| 31 | + private Integer status; // 参见 CommonStatusEnum 枚举类(0 启用 / 1 禁用) | ||
| 32 | + | ||
| 33 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.dal.dataobject.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 5 | +import com.baomidou.mybatisplus.annotation.KeySequence; | ||
| 6 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 8 | +import lombok.*; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * IM 表情包 DO(运营配置的系统表情包元数据) | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@TableName("im_face_pack") | ||
| 16 | +@KeySequence("im_face_pack_seq") | ||
| 17 | +@Data | ||
| 18 | +@EqualsAndHashCode(callSuper = true) | ||
| 19 | +@ToString(callSuper = true) | ||
| 20 | +@Builder | ||
| 21 | +@NoArgsConstructor | ||
| 22 | +@AllArgsConstructor | ||
| 23 | +public class ImFacePackDO extends BaseDO { | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 编号 | ||
| 27 | + */ | ||
| 28 | + @TableId | ||
| 29 | + private Long id; | ||
| 30 | + /** | ||
| 31 | + * 表情包名称 | ||
| 32 | + */ | ||
| 33 | + private String name; | ||
| 34 | + // TODO @AI:icon 一般不带 url;类似 avatar,特有单词; | ||
| 35 | + /** | ||
| 36 | + * 表情包图标 URL | ||
| 37 | + * <p> | ||
| 38 | + * 面板底部 tab 栏显示 | ||
| 39 | + */ | ||
| 40 | + private String iconUrl; | ||
| 41 | + /** | ||
| 42 | + * 排序 | ||
| 43 | + */ | ||
| 44 | + private Integer sort; | ||
| 45 | + /** | ||
| 46 | + * 状态 | ||
| 47 | + * <p> | ||
| 48 | + * 枚举 {@link CommonStatusEnum} | ||
| 49 | + */ | ||
| 50 | + private Integer status; | ||
| 51 | + | ||
| 52 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFacePackItemDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.dal.dataobject.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 5 | +import com.baomidou.mybatisplus.annotation.KeySequence; | ||
| 6 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 7 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 8 | +import lombok.*; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * IM 表情包项 DO(系统表情包内的单张表情图) | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@TableName("im_face_pack_item") | ||
| 16 | +@KeySequence("im_face_pack_item_seq") | ||
| 17 | +@Data | ||
| 18 | +@EqualsAndHashCode(callSuper = true) | ||
| 19 | +@ToString(callSuper = true) | ||
| 20 | +@Builder | ||
| 21 | +@NoArgsConstructor | ||
| 22 | +@AllArgsConstructor | ||
| 23 | +public class ImFacePackItemDO extends BaseDO { | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 编号 | ||
| 27 | + */ | ||
| 28 | + @TableId | ||
| 29 | + private Long id; | ||
| 30 | + /** | ||
| 31 | + * 所属表情包编号 | ||
| 32 | + */ | ||
| 33 | + private Long packId; | ||
| 34 | + /** | ||
| 35 | + * 表情图 URL | ||
| 36 | + */ | ||
| 37 | + private String url; | ||
| 38 | + /** | ||
| 39 | + * 表情名(可选;如「狗头」「捂脸」) | ||
| 40 | + */ | ||
| 41 | + private String name; | ||
| 42 | + /** | ||
| 43 | + * 渲染宽度(像素) | ||
| 44 | + */ | ||
| 45 | + private Integer width; | ||
| 46 | + /** | ||
| 47 | + * 渲染高度(像素) | ||
| 48 | + */ | ||
| 49 | + private Integer height; | ||
| 50 | + /** | ||
| 51 | + * 排序 | ||
| 52 | + */ | ||
| 53 | + private Integer sort; | ||
| 54 | + /** | ||
| 55 | + * 状态 | ||
| 56 | + * <p> | ||
| 57 | + * 枚举 {@link CommonStatusEnum} | ||
| 58 | + */ | ||
| 59 | + private Integer status; | ||
| 60 | + | ||
| 61 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/face/ImFaceUserItemDO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.dal.dataobject.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 4 | +import com.baomidou.mybatisplus.annotation.KeySequence; | ||
| 5 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 6 | +import com.baomidou.mybatisplus.annotation.TableName; | ||
| 7 | +import lombok.*; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * IM 用户私有表情 DO(个人表情包,对照微信「我的表情」) | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@TableName("im_face_user_item") | ||
| 15 | +@KeySequence("im_face_user_item_seq") | ||
| 16 | +@Data | ||
| 17 | +@EqualsAndHashCode(callSuper = true) | ||
| 18 | +@ToString(callSuper = true) | ||
| 19 | +@Builder | ||
| 20 | +@NoArgsConstructor | ||
| 21 | +@AllArgsConstructor | ||
| 22 | +public class ImFaceUserItemDO extends BaseDO { | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * 编号 | ||
| 26 | + */ | ||
| 27 | + @TableId | ||
| 28 | + private Long id; | ||
| 29 | + /** | ||
| 30 | + * 所属用户编号 | ||
| 31 | + * | ||
| 32 | + * // TODO @AI:是不是要关联下 userid | ||
| 33 | + */ | ||
| 34 | + private Long userId; | ||
| 35 | + /** | ||
| 36 | + * 表情图 URL | ||
| 37 | + */ | ||
| 38 | + private String url; | ||
| 39 | + /** | ||
| 40 | + * 表情名(可选) | ||
| 41 | + * <p> | ||
| 42 | + * 用户私有表情通常不带名字,留字段以备将来「重命名」交互 | ||
| 43 | + */ | ||
| 44 | + private String name; | ||
| 45 | + /** | ||
| 46 | + * 渲染宽度(像素) | ||
| 47 | + */ | ||
| 48 | + private Integer width; | ||
| 49 | + /** | ||
| 50 | + * 渲染高度(像素) | ||
| 51 | + */ | ||
| 52 | + private Integer height; | ||
| 53 | + /** | ||
| 54 | + * 来源消息编号 | ||
| 55 | + * <p> | ||
| 56 | + * 从消息「添加到表情」时记录;自己上传则为 NULL;用于排查 / 后续溯源 | ||
| 57 | + * | ||
| 58 | + * TODO @AI:关联字段; | ||
| 59 | + */ | ||
| 60 | + private Long sourceMessageId; | ||
| 61 | + /** | ||
| 62 | + * 排序 | ||
| 63 | + */ | ||
| 64 | + private Integer sort; | ||
| 65 | + | ||
| 66 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackItemMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.dal.mysql.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 6 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackItemPageReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | + | ||
| 10 | +import java.util.Collection; | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * IM 表情包项 Mapper | ||
| 15 | + * | ||
| 16 | + * @author 芋道源码 | ||
| 17 | + */ | ||
| 18 | +@Mapper | ||
| 19 | +public interface ImFacePackItemMapper extends BaseMapperX<ImFacePackItemDO> { | ||
| 20 | + | ||
| 21 | + default List<ImFacePackItemDO> selectListByPackIdsAndStatus(Collection<Long> packIds, Integer status) { | ||
| 22 | + return selectList(new LambdaQueryWrapperX<ImFacePackItemDO>() | ||
| 23 | + .inIfPresent(ImFacePackItemDO::getPackId, packIds) | ||
| 24 | + .eq(ImFacePackItemDO::getStatus, status) | ||
| 25 | + .orderByAsc(ImFacePackItemDO::getPackId) | ||
| 26 | + .orderByAsc(ImFacePackItemDO::getSort) | ||
| 27 | + .orderByAsc(ImFacePackItemDO::getId)); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + default Long selectCountByPackId(Long packId) { | ||
| 31 | + return selectCount(new LambdaQueryWrapperX<ImFacePackItemDO>() | ||
| 32 | + .eq(ImFacePackItemDO::getPackId, packId)); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + default Long selectCountByPackIds(Collection<Long> packIds) { | ||
| 36 | + return selectCount(new LambdaQueryWrapperX<ImFacePackItemDO>() | ||
| 37 | + .in(ImFacePackItemDO::getPackId, packIds)); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + default PageResult<ImFacePackItemDO> selectPage(ImFacePackItemPageReqVO reqVO) { | ||
| 41 | + return selectPage(reqVO, new LambdaQueryWrapperX<ImFacePackItemDO>() | ||
| 42 | + .eqIfPresent(ImFacePackItemDO::getPackId, reqVO.getPackId()) | ||
| 43 | + .likeIfPresent(ImFacePackItemDO::getName, reqVO.getName()) | ||
| 44 | + .eqIfPresent(ImFacePackItemDO::getStatus, reqVO.getStatus()) | ||
| 45 | + .orderByAsc(ImFacePackItemDO::getSort) | ||
| 46 | + .orderByDesc(ImFacePackItemDO::getId)); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFacePackMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.dal.mysql.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 6 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackPageReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO; | ||
| 8 | +import org.apache.ibatis.annotations.Mapper; | ||
| 9 | + | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * IM 表情包 Mapper | ||
| 14 | + * | ||
| 15 | + * @author 芋道源码 | ||
| 16 | + */ | ||
| 17 | +@Mapper | ||
| 18 | +public interface ImFacePackMapper extends BaseMapperX<ImFacePackDO> { | ||
| 19 | + | ||
| 20 | + default List<ImFacePackDO> selectListByStatusOrderBySort(Integer status) { | ||
| 21 | + return selectList(new LambdaQueryWrapperX<ImFacePackDO>() | ||
| 22 | + .eq(ImFacePackDO::getStatus, status) | ||
| 23 | + .orderByAsc(ImFacePackDO::getSort) | ||
| 24 | + .orderByAsc(ImFacePackDO::getId)); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + default PageResult<ImFacePackDO> selectPage(ImFacePackPageReqVO reqVO) { | ||
| 28 | + return selectPage(reqVO, new LambdaQueryWrapperX<ImFacePackDO>() | ||
| 29 | + .likeIfPresent(ImFacePackDO::getName, reqVO.getName()) | ||
| 30 | + .eqIfPresent(ImFacePackDO::getStatus, reqVO.getStatus()) | ||
| 31 | + .betweenIfPresent(ImFacePackDO::getCreateTime, reqVO.getCreateTime()) | ||
| 32 | + .orderByAsc(ImFacePackDO::getSort) | ||
| 33 | + .orderByDesc(ImFacePackDO::getId)); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/face/ImFaceUserItemMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.dal.mysql.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 5 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; | ||
| 6 | +import org.apache.ibatis.annotations.Mapper; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * IM 用户私有表情 Mapper | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Mapper | ||
| 16 | +public interface ImFaceUserItemMapper extends BaseMapperX<ImFaceUserItemDO> { | ||
| 17 | + | ||
| 18 | + /** 取用户的所有个人表情,按 sort 升序、id 倒序(最近添加在前) */ | ||
| 19 | + default List<ImFaceUserItemDO> selectListByUserId(Long userId) { | ||
| 20 | + return selectList(new LambdaQueryWrapperX<ImFaceUserItemDO>() | ||
| 21 | + .eq(ImFaceUserItemDO::getUserId, userId) | ||
| 22 | + .orderByAsc(ImFaceUserItemDO::getSort) | ||
| 23 | + .orderByDesc(ImFaceUserItemDO::getId)); | ||
| 24 | + } | ||
| 25 | + | ||
| 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) { | ||
| 32 | + return selectOne(new LambdaQueryWrapperX<ImFaceUserItemDO>() | ||
| 33 | + .eq(ImFaceUserItemDO::getUserId, userId) | ||
| 34 | + .eq(ImFaceUserItemDO::getUrl, url)); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/enums/message/ImMessageTypeEnum.java
| @@ -49,6 +49,12 @@ public enum ImMessageTypeEnum implements ArrayValuable<Integer> { | @@ -49,6 +49,12 @@ public enum ImMessageTypeEnum implements ArrayValuable<Integer> { | ||
| 49 | * 场景:把好友名片推荐给其他会话,对端点击名片可打开 UserInfoCard | 49 | * 场景:把好友名片推荐给其他会话,对端点击名片可打开 UserInfoCard |
| 50 | */ | 50 | */ |
| 51 | CARD(108, "名片", true, true), | 51 | CARD(108, "名片", true, true), |
| 52 | + /** | ||
| 53 | + * 对应 OpenIM:Face 115 | ||
| 54 | + * 对应自己的类:FaceMessage | ||
| 55 | + * 场景:表情贴图(运营配置的系统表情包 + 用户私有表情包);Unicode emoji 仍走 TEXT | ||
| 56 | + */ | ||
| 57 | + FACE(115, "表情", true, true), | ||
| 52 | 58 | ||
| 53 | // ========== 信号类(2101 / 2200 直接复用 OpenIM 段位编号;2201 自有扩展) ========== | 59 | // ========== 信号类(2101 / 2200 直接复用 OpenIM 段位编号;2201 自有扩展) ========== |
| 54 | /** | 60 | /** |
| @@ -142,9 +148,10 @@ public enum ImMessageTypeEnum implements ArrayValuable<Integer> { | @@ -142,9 +148,10 @@ public enum ImMessageTypeEnum implements ArrayValuable<Integer> { | ||
| 142 | GROUP_INFO_UPDATE(1502, "群信息变更", true, false), | 148 | GROUP_INFO_UPDATE(1502, "群信息变更", true, false), |
| 143 | /** | 149 | /** |
| 144 | * 对应 OpenIM:sdkws.JoinGroupApplicationTips(JoinGroupApplicationNotification 1503) | 150 | * 对应 OpenIM:sdkws.JoinGroupApplicationTips(JoinGroupApplicationNotification 1503) |
| 145 | - * TODO @AI 未实现:入群申请;本期不在范围,预留段位以便未来对齐 OpenIM | 151 | + * 对应自己的类:GroupRequestNotification |
| 152 | + * 场景:用户申请加群 / 普通成员邀请待审批,定向私聊推送给群主 + 全部管理员(多端同步);不入群消息流 | ||
| 146 | */ | 153 | */ |
| 147 | - GROUP_JOIN_APPLICATION(1503, "入群申请", true, false), | 154 | + GROUP_REQUEST_RECEIVED(1503, "收到新的入群申请", false, false), |
| 148 | /** | 155 | /** |
| 149 | * 对应 OpenIM:sdkws.MemberQuitTips(MemberQuitNotification 1504) | 156 | * 对应 OpenIM:sdkws.MemberQuitTips(MemberQuitNotification 1504) |
| 150 | * 对应自己的类:GroupMemberQuitNotification | 157 | * 对应自己的类:GroupMemberQuitNotification |
| @@ -153,14 +160,16 @@ public enum ImMessageTypeEnum implements ArrayValuable<Integer> { | @@ -153,14 +160,16 @@ public enum ImMessageTypeEnum implements ArrayValuable<Integer> { | ||
| 153 | GROUP_MEMBER_QUIT(1504, "成员退群", true, false), | 160 | GROUP_MEMBER_QUIT(1504, "成员退群", true, false), |
| 154 | /** | 161 | /** |
| 155 | * 对应 OpenIM:sdkws.GroupApplicationAcceptedTips(GroupApplicationAcceptedNotification 1505) | 162 | * 对应 OpenIM:sdkws.GroupApplicationAcceptedTips(GroupApplicationAcceptedNotification 1505) |
| 156 | - * TODO @AI 未实现:入群申请通过;本期不在范围 | 163 | + * 对应自己的类:GroupRequestApprovedNotification |
| 164 | + * 场景:群主 / 管理员同意申请,定向私聊推送给申请人 + 群主 + 全部管理员;申请人侧弹 toast,admin 侧 pendingRequestCount-1;不入群消息流 | ||
| 157 | */ | 165 | */ |
| 158 | - GROUP_APPLICATION_ACCEPTED(1505, "入群申请通过", true, false), | 166 | + GROUP_REQUEST_APPROVED(1505, "入群申请被同意", false, false), |
| 159 | /** | 167 | /** |
| 160 | * 对应 OpenIM:sdkws.GroupApplicationRejectedTips(GroupApplicationRejectedNotification 1506) | 168 | * 对应 OpenIM:sdkws.GroupApplicationRejectedTips(GroupApplicationRejectedNotification 1506) |
| 161 | - * TODO @AI 未实现:入群申请拒绝;本期不在范围 | 169 | + * 对应自己的类:GroupRequestRejectedNotification |
| 170 | + * 场景:群主 / 管理员拒绝申请,定向私聊推送给申请人 + 群主 + 全部管理员;不入群消息流 | ||
| 162 | */ | 171 | */ |
| 163 | - GROUP_APPLICATION_REJECTED(1506, "入群申请拒绝", true, false), | 172 | + GROUP_REQUEST_REJECTED(1506, "入群申请被拒绝", false, false), |
| 164 | /** | 173 | /** |
| 165 | * 对应 OpenIM:sdkws.GroupOwnerTransferredTips(GroupOwnerTransferredNotification 1507) | 174 | * 对应 OpenIM:sdkws.GroupOwnerTransferredTips(GroupOwnerTransferredNotification 1507) |
| 166 | * 对应自己的类:GroupOwnerTransferNotification | 175 | * 对应自己的类:GroupOwnerTransferNotification |
| @@ -181,7 +190,8 @@ public enum ImMessageTypeEnum implements ArrayValuable<Integer> { | @@ -181,7 +190,8 @@ public enum ImMessageTypeEnum implements ArrayValuable<Integer> { | ||
| 181 | GROUP_MEMBER_INVITE(1509, "成员加入", true, false), | 190 | GROUP_MEMBER_INVITE(1509, "成员加入", true, false), |
| 182 | /** | 191 | /** |
| 183 | * 对应 OpenIM:sdkws.MemberEnterTips(MemberEnterNotification 1510) | 192 | * 对应 OpenIM:sdkws.MemberEnterTips(MemberEnterNotification 1510) |
| 184 | - * TODO @AI 未实现:自由进群(链接 / 二维码进群);本期不在范围 | 193 | + * 对应自己的类:GroupMemberEnterNotification |
| 194 | + * 场景:用户经搜索 / 二维码 / 分享链接自由进群(FREE 模式或审批通过后),全员广播;前端按 entrantUserId 局部添加成员 | ||
| 185 | */ | 195 | */ |
| 186 | GROUP_MEMBER_ENTER(1510, "自由进群", true, false), | 196 | GROUP_MEMBER_ENTER(1510, "自由进群", true, false), |
| 187 | /** | 197 | /** |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.service.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackItemPageReqVO; | ||
| 5 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackItemSaveReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO; | ||
| 7 | +import jakarta.validation.Valid; | ||
| 8 | + | ||
| 9 | +import java.util.Collection; | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * IM 表情包项 Service 接口 | ||
| 14 | + * | ||
| 15 | + * @author 芋道源码 | ||
| 16 | + */ | ||
| 17 | +public interface ImFacePackItemService { | ||
| 18 | + | ||
| 19 | + // ==================== 用户端 ==================== | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 【用户端】按 packIds 批量取启用项,给前端聚合接口用 | ||
| 23 | + */ | ||
| 24 | + List<ImFacePackItemDO> getEnabledItemListByPackIds(Collection<Long> packIds); | ||
| 25 | + | ||
| 26 | + // ==================== 管理后台 ==================== | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 【管理后台】分页查询 | ||
| 30 | + */ | ||
| 31 | + PageResult<ImFacePackItemDO> getFacePackItemPage(ImFacePackItemPageReqVO reqVO); | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 【管理后台】获取详情 | ||
| 35 | + */ | ||
| 36 | + ImFacePackItemDO getFacePackItem(Long id); | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 【管理后台】新增,返回新增 id | ||
| 40 | + */ | ||
| 41 | + Long createFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * 【管理后台】修改 | ||
| 45 | + */ | ||
| 46 | + void updateFacePackItem(@Valid ImFacePackItemSaveReqVO reqVO); | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * 【管理后台】删除 | ||
| 50 | + */ | ||
| 51 | + void deleteFacePackItem(Long id); | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * 【管理后台】批量删除 | ||
| 55 | + */ | ||
| 56 | + void deleteFacePackItemList(List<Long> ids); | ||
| 57 | + | ||
| 58 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackItemServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.service.face; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 6 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 7 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackItemPageReqVO; | ||
| 8 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackItemSaveReqVO; | ||
| 9 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackItemDO; | ||
| 10 | +import cn.iocoder.yudao.module.im.dal.mysql.face.ImFacePackItemMapper; | ||
| 11 | +import jakarta.annotation.Resource; | ||
| 12 | +import org.springframework.stereotype.Service; | ||
| 13 | +import org.springframework.validation.annotation.Validated; | ||
| 14 | + | ||
| 15 | +import java.util.Collection; | ||
| 16 | +import java.util.Collections; | ||
| 17 | +import java.util.List; | ||
| 18 | + | ||
| 19 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 20 | +import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_ITEM_NOT_EXISTS; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * IM 表情包项 Service 实现类 | ||
| 24 | + * | ||
| 25 | + * @author 芋道源码 | ||
| 26 | + */ | ||
| 27 | +@Service | ||
| 28 | +@Validated | ||
| 29 | +public class ImFacePackItemServiceImpl implements ImFacePackItemService { | ||
| 30 | + | ||
| 31 | + @Resource | ||
| 32 | + private ImFacePackItemMapper facePackItemMapper; | ||
| 33 | + @Resource | ||
| 34 | + private ImFacePackService facePackService; | ||
| 35 | + | ||
| 36 | + // ==================== 用户端 ==================== | ||
| 37 | + | ||
| 38 | + @Override | ||
| 39 | + public List<ImFacePackItemDO> getEnabledItemListByPackIds(Collection<Long> packIds) { | ||
| 40 | + if (CollUtil.isEmpty(packIds)) { | ||
| 41 | + return Collections.emptyList(); | ||
| 42 | + } | ||
| 43 | + return facePackItemMapper.selectListByPackIdsAndStatus(packIds, CommonStatusEnum.ENABLE.getStatus()); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + // ==================== 管理后台 ==================== | ||
| 47 | + | ||
| 48 | + @Override | ||
| 49 | + public PageResult<ImFacePackItemDO> getFacePackItemPage(ImFacePackItemPageReqVO reqVO) { | ||
| 50 | + return facePackItemMapper.selectPage(reqVO); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public ImFacePackItemDO getFacePackItem(Long id) { | ||
| 55 | + return facePackItemMapper.selectById(id); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + @Override | ||
| 59 | + public Long createFacePackItem(ImFacePackItemSaveReqVO reqVO) { | ||
| 60 | + // 校验所属表情包存在 | ||
| 61 | + facePackService.validateFacePackExists(reqVO.getPackId()); | ||
| 62 | + ImFacePackItemDO item = BeanUtils.toBean(reqVO, ImFacePackItemDO.class); | ||
| 63 | + | ||
| 64 | + // TODO @AI:注释风格,和别的模块一致 | ||
| 65 | + facePackItemMapper.insert(item); | ||
| 66 | + return item.getId(); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + @Override | ||
| 70 | + public void updateFacePackItem(ImFacePackItemSaveReqVO reqVO) { | ||
| 71 | + // TODO @AI:注释风格,和别的模块一致 | ||
| 72 | + validateFacePackItemExists(reqVO.getId()); | ||
| 73 | + // TODO @AI:注释风格,和别的模块一致 | ||
| 74 | + facePackService.validateFacePackExists(reqVO.getPackId()); | ||
| 75 | + | ||
| 76 | + // TODO @AI:注释风格,和别的模块一致 | ||
| 77 | + ImFacePackItemDO updateObj = BeanUtils.toBean(reqVO, ImFacePackItemDO.class); | ||
| 78 | + facePackItemMapper.updateById(updateObj); | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + @Override | ||
| 82 | + public void deleteFacePackItem(Long id) { | ||
| 83 | + // TODO @AI:注释风格,和别的模块一致 | ||
| 84 | + validateFacePackItemExists(id); | ||
| 85 | + // TODO @AI:注释风格,和别的模块一致 | ||
| 86 | + facePackItemMapper.deleteById(id); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + @Override | ||
| 90 | + public void deleteFacePackItemList(List<Long> ids) { | ||
| 91 | + if (CollUtil.isEmpty(ids)) { | ||
| 92 | + return; | ||
| 93 | + } | ||
| 94 | + facePackItemMapper.deleteByIds(ids); | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + private void validateFacePackItemExists(Long id) { | ||
| 98 | + if (facePackItemMapper.selectById(id) == null) { | ||
| 99 | + throw exception(FACE_PACK_ITEM_NOT_EXISTS); | ||
| 100 | + } | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.service.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackPageReqVO; | ||
| 5 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackSaveReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO; | ||
| 7 | +import jakarta.validation.Valid; | ||
| 8 | + | ||
| 9 | +import java.util.List; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * IM 表情包 Service 接口 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +public interface ImFacePackService { | ||
| 17 | + | ||
| 18 | + // TODO @AI:已经区分了 === 就不用写【用户端】【管理后台】了。 | ||
| 19 | + | ||
| 20 | + // ==================== 用户端 ==================== | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 【用户端】获取所有启用的表情包,按 sort 升序 | ||
| 24 | + */ | ||
| 25 | + List<ImFacePackDO> getEnabledFacePackList(); | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 校验表情包存在 | ||
| 29 | + */ | ||
| 30 | + @SuppressWarnings("UnusedReturnValue") | ||
| 31 | + ImFacePackDO validateFacePackExists(Long id); | ||
| 32 | + | ||
| 33 | + // ==================== 管理后台 ==================== | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 【管理后台】分页查询表情包 | ||
| 37 | + */ | ||
| 38 | + PageResult<ImFacePackDO> getFacePackPage(ImFacePackPageReqVO reqVO); | ||
| 39 | + | ||
| 40 | + /** | ||
| 41 | + * 【管理后台】获取表情包详情 | ||
| 42 | + */ | ||
| 43 | + ImFacePackDO getFacePack(Long id); | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * 【管理后台】新增表情包,返回新增 id | ||
| 47 | + */ | ||
| 48 | + Long createFacePack(@Valid ImFacePackSaveReqVO reqVO); | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 【管理后台】修改表情包 | ||
| 52 | + */ | ||
| 53 | + void updateFacePack(@Valid ImFacePackSaveReqVO reqVO); | ||
| 54 | + | ||
| 55 | + /** | ||
| 56 | + * 【管理后台】删除表情包;存在表情时拒绝 | ||
| 57 | + */ | ||
| 58 | + void deleteFacePack(Long id); | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * 【管理后台】批量删除表情包 | ||
| 62 | + */ | ||
| 63 | + void deleteFacePackList(List<Long> ids); | ||
| 64 | + | ||
| 65 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFacePackServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.service.face; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 5 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 6 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 7 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackPageReqVO; | ||
| 8 | +import cn.iocoder.yudao.module.im.controller.admin.manager.face.vo.ImFacePackSaveReqVO; | ||
| 9 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFacePackDO; | ||
| 10 | +import cn.iocoder.yudao.module.im.dal.mysql.face.ImFacePackItemMapper; | ||
| 11 | +import cn.iocoder.yudao.module.im.dal.mysql.face.ImFacePackMapper; | ||
| 12 | +import jakarta.annotation.Resource; | ||
| 13 | +import org.springframework.stereotype.Service; | ||
| 14 | +import org.springframework.validation.annotation.Validated; | ||
| 15 | + | ||
| 16 | +import java.util.List; | ||
| 17 | + | ||
| 18 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 19 | +import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_HAS_ITEMS; | ||
| 20 | +import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_PACK_NOT_EXISTS; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * IM 表情包 Service 实现类 | ||
| 24 | + * | ||
| 25 | + * @author 芋道源码 | ||
| 26 | + */ | ||
| 27 | +@Service | ||
| 28 | +@Validated | ||
| 29 | +public class ImFacePackServiceImpl implements ImFacePackService { | ||
| 30 | + | ||
| 31 | + @Resource | ||
| 32 | + private ImFacePackMapper facePackMapper; | ||
| 33 | + | ||
| 34 | + // TODO @AI:跨模块操作,需要调用对方 service; | ||
| 35 | + @Resource | ||
| 36 | + private ImFacePackItemMapper facePackItemMapper; | ||
| 37 | + | ||
| 38 | + // ==================== 用户端 ==================== | ||
| 39 | + | ||
| 40 | + @Override | ||
| 41 | + public List<ImFacePackDO> getEnabledFacePackList() { | ||
| 42 | + return facePackMapper.selectListByStatusOrderBySort(CommonStatusEnum.ENABLE.getStatus()); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + @Override | ||
| 46 | + public ImFacePackDO validateFacePackExists(Long id) { | ||
| 47 | + ImFacePackDO pack = facePackMapper.selectById(id); | ||
| 48 | + if (pack == null) { | ||
| 49 | + throw exception(FACE_PACK_NOT_EXISTS); | ||
| 50 | + } | ||
| 51 | + return pack; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + // ==================== 管理后台 ==================== | ||
| 55 | + | ||
| 56 | + @Override | ||
| 57 | + public PageResult<ImFacePackDO> getFacePackPage(ImFacePackPageReqVO reqVO) { | ||
| 58 | + return facePackMapper.selectPage(reqVO); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + @Override | ||
| 62 | + public ImFacePackDO getFacePack(Long id) { | ||
| 63 | + return facePackMapper.selectById(id); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + @Override | ||
| 67 | + public Long createFacePack(ImFacePackSaveReqVO reqVO) { | ||
| 68 | + ImFacePackDO pack = BeanUtils.toBean(reqVO, ImFacePackDO.class); | ||
| 69 | + facePackMapper.insert(pack); | ||
| 70 | + return pack.getId(); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + @Override | ||
| 74 | + public void updateFacePack(ImFacePackSaveReqVO reqVO) { | ||
| 75 | + // TODO @AI:注释,参考别的模块 | ||
| 76 | + validateFacePackExists(reqVO.getId()); | ||
| 77 | + | ||
| 78 | + // TODO @AI:注释,参考别的模块 | ||
| 79 | + ImFacePackDO updateObj = BeanUtils.toBean(reqVO, ImFacePackDO.class); | ||
| 80 | + facePackMapper.updateById(updateObj); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + @Override | ||
| 84 | + public void deleteFacePack(Long id) { | ||
| 85 | + // 1.1 校验存在 | ||
| 86 | + validateFacePackExists(id); | ||
| 87 | + // 1.2 校验表情包下没有表情;防止误删表情包导致历史 face 消息无法回查归属 | ||
| 88 | + if (facePackItemMapper.selectCountByPackId(id) > 0) { | ||
| 89 | + throw exception(FACE_PACK_HAS_ITEMS); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + // 2. 删除 | ||
| 93 | + facePackMapper.deleteById(id); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + @Override | ||
| 97 | + public void deleteFacePackList(List<Long> ids) { | ||
| 98 | + if (CollUtil.isEmpty(ids)) { | ||
| 99 | + return; | ||
| 100 | + } | ||
| 101 | + // 任一存在表情则拒绝整批删除,避免「只删一半」的中间态 | ||
| 102 | + if (facePackItemMapper.selectCountByPackIds(ids) > 0) { | ||
| 103 | + throw exception(FACE_PACK_HAS_ITEMS); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + // 执行删除 | ||
| 107 | + facePackMapper.deleteByIds(ids); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.service.face; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.im.controller.admin.face.vo.ImFaceUserItemSaveReqVO; | ||
| 4 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; | ||
| 5 | +import jakarta.validation.Valid; | ||
| 6 | + | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * IM 用户私有表情 Service 接口 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +public interface ImFaceUserItemService { | ||
| 15 | + | ||
| 16 | + /** | ||
| 17 | + * 获取我的个人表情列表 | ||
| 18 | + */ | ||
| 19 | + List<ImFaceUserItemDO> getMyFaceUserItemList(Long userId); | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 添加个人表情;返回新增 id(已存在则直接返回旧 id) | ||
| 23 | + * <p> | ||
| 24 | + * 同 URL 重复添加时返回旧记录 id,不报错 | ||
| 25 | + */ | ||
| 26 | + Long createFaceUserItem(Long userId, @Valid ImFaceUserItemSaveReqVO reqVO); | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 删除我的某条个人表情 | ||
| 30 | + */ | ||
| 31 | + void deleteFaceUserItem(Long userId, Long id); | ||
| 32 | + | ||
| 33 | + /** | ||
| 34 | + * 批量删除我的个人表情 | ||
| 35 | + */ | ||
| 36 | + void deleteFaceUserItemList(Long userId, List<Long> ids); | ||
| 37 | + | ||
| 38 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/face/ImFaceUserItemServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.service.face; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | ||
| 5 | +import cn.iocoder.yudao.module.im.controller.admin.face.vo.ImFaceUserItemSaveReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.im.dal.dataobject.face.ImFaceUserItemDO; | ||
| 7 | +import cn.iocoder.yudao.module.im.dal.mysql.face.ImFaceUserItemMapper; | ||
| 8 | +import jakarta.annotation.Resource; | ||
| 9 | +import org.springframework.stereotype.Service; | ||
| 10 | +import org.springframework.validation.annotation.Validated; | ||
| 11 | + | ||
| 12 | +import java.util.List; | ||
| 13 | + | ||
| 14 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 15 | +import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_NOT_EXISTS; | ||
| 16 | +import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FACE_USER_ITEM_NOT_OWN; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * IM 用户私有表情 Service 实现类 | ||
| 20 | + * | ||
| 21 | + * @author 芋道源码 | ||
| 22 | + */ | ||
| 23 | +@Service | ||
| 24 | +@Validated | ||
| 25 | +public class ImFaceUserItemServiceImpl implements ImFaceUserItemService { | ||
| 26 | + | ||
| 27 | + @Resource | ||
| 28 | + private ImFaceUserItemMapper faceUserItemMapper; | ||
| 29 | + | ||
| 30 | + // TODO @AI:传递了 userid,就不用写 myXXX 了; | ||
| 31 | + @Override | ||
| 32 | + public List<ImFaceUserItemDO> getMyFaceUserItemList(Long userId) { | ||
| 33 | + return faceUserItemMapper.selectListByUserId(userId); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + @Override | ||
| 37 | + public Long createFaceUserItem(Long userId, ImFaceUserItemSaveReqVO reqVO) { | ||
| 38 | + // 1. 同 URL 已添加:直接返回旧 id;避免一张图反复添加占额度,并保证「添加到表情」幂等 | ||
| 39 | + // TODO @AI:是不是提示下,已经有这个标签库了。。。 | ||
| 40 | + ImFaceUserItemDO exist = faceUserItemMapper.selectByUserIdAndUrl(userId, reqVO.getUrl()); | ||
| 41 | + if (exist != null) { | ||
| 42 | + return exist.getId(); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + // 2. 入库 | ||
| 46 | + // TODO @AI:链式调用 | ||
| 47 | + ImFaceUserItemDO item = BeanUtils.toBean(reqVO, ImFaceUserItemDO.class); | ||
| 48 | + item.setUserId(userId); | ||
| 49 | + item.setSort(0); | ||
| 50 | + faceUserItemMapper.insert(item); | ||
| 51 | + return item.getId(); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Override | ||
| 55 | + public void deleteFaceUserItem(Long userId, Long id) { | ||
| 56 | + ImFaceUserItemDO item = faceUserItemMapper.selectById(id); | ||
| 57 | + if (item == null) { | ||
| 58 | + throw exception(FACE_USER_ITEM_NOT_EXISTS); | ||
| 59 | + } | ||
| 60 | + // 防止 A 用户传 B 用户的表情 id 删除别人的表情 | ||
| 61 | + // TODO @AI:notEquals; | ||
| 62 | + if (!item.getUserId().equals(userId)) { | ||
| 63 | + throw exception(FACE_USER_ITEM_NOT_OWN); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + // TODO @AI:注释 | ||
| 67 | + faceUserItemMapper.deleteById(id); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + @Override | ||
| 71 | + public void deleteFaceUserItemList(Long userId, List<Long> ids) { | ||
| 72 | + if (CollUtil.isEmpty(ids)) { | ||
| 73 | + return; | ||
| 74 | + } | ||
| 75 | + // 一次性查全部待删项;任一不属于当前用户则整批拒绝 | ||
| 76 | + // TODO @AI:过滤掉,不属于自己的; | ||
| 77 | + List<ImFaceUserItemDO> items = faceUserItemMapper.selectByIds(ids); | ||
| 78 | + // TODO @AI:不存在的,直接跳过; | ||
| 79 | + if (CollUtil.size(items) != CollUtil.size(ids)) { | ||
| 80 | + throw exception(FACE_USER_ITEM_NOT_EXISTS); | ||
| 81 | + } | ||
| 82 | + for (ImFaceUserItemDO item : items) { | ||
| 83 | + if (!item.getUserId().equals(userId)) { | ||
| 84 | + throw exception(FACE_USER_ITEM_NOT_OWN); | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + // TODO @AI:注释 | ||
| 89 | + faceUserItemMapper.deleteByIds(ids); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | +} |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/dto/message/FaceMessage.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.im.service.websocket.dto.message; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 表情消息内容 | ||
| 7 | + * <p> | ||
| 8 | + * 承载「贴图 / 自定义表情包」类消息;Unicode emoji(😀😂)仍走 TEXT | ||
| 9 | + */ | ||
| 10 | +@Data | ||
| 11 | +public class FaceMessage { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 表情图 URL | ||
| 15 | + */ | ||
| 16 | + private String url; | ||
| 17 | + // TODO @AI:openim 有这个字段么?不是一般 url 就足够了呀。 | ||
| 18 | + /** | ||
| 19 | + * 渲染宽度(像素) | ||
| 20 | + * <p> | ||
| 21 | + * 客户端渲染时按此尺寸占位,避免图片加载完成后的布局抖动 | ||
| 22 | + */ | ||
| 23 | + private Integer width; | ||
| 24 | + /** | ||
| 25 | + * 渲染高度(像素) | ||
| 26 | + */ | ||
| 27 | + private Integer height; | ||
| 28 | + /** | ||
| 29 | + * 表情名(可选) | ||
| 30 | + * <p> | ||
| 31 | + * 系统表情包通常带名字(如「狗头」「捂脸」),用户私有表情包通常为空 | ||
| 32 | + */ | ||
| 33 | + private String name; | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * 引用消息(可选) | ||
| 37 | + */ | ||
| 38 | + private QuoteMessage quote; | ||
| 39 | + | ||
| 40 | +} |