feat(ai-companion): 新增AI角色点赞功能
新增点赞/取消点赞接口,包含实体、Mapper、Service及DTO,支持用户点赞状态切换与异常处理。
This commit is contained in:
@@ -2,6 +2,6 @@
|
||||
"active": true,
|
||||
"started_at": "2026-01-26T13:01:18.447Z",
|
||||
"original_prompt": "刚刚回滚了代码,现在AI陪聊角色评论需要使用KeyboardAiCompanionCommentLikeService添加一个评论点赞接口,用来记录点赞和取消点赞。 ulw",
|
||||
"reinforcement_count": 5,
|
||||
"last_checked_at": "2026-01-27T05:14:53.054Z"
|
||||
"reinforcement_count": 7,
|
||||
"last_checked_at": "2026-01-27T10:31:33.079Z"
|
||||
}
|
||||
@@ -30,6 +30,7 @@ public enum ErrorCode {
|
||||
CHAT_SAVE_DATA_EMPTY(40010, "保存数据不能为空"),
|
||||
COMPANION_MESSAGE_EMPTY(40011, "消息内容不能为空"),
|
||||
COMPANION_ID_EMPTY(40012, "AI陪聊角色ID不能为空"),
|
||||
COMPANION_NOT_FOUND(40019, "AI陪聊角色不存在"),
|
||||
COMMENT_CONTENT_EMPTY(40013, "评论内容不能为空"),
|
||||
COMMENT_NOT_FOUND(40014, "评论不存在"),
|
||||
COMMENT_ID_EMPTY(40015, "评论ID不能为空"),
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
package com.yolo.keyborad.controller;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.yolo.keyborad.common.BaseResponse;
|
||||
import com.yolo.keyborad.common.ErrorCode;
|
||||
import com.yolo.keyborad.common.ResultUtils;
|
||||
import com.yolo.keyborad.exception.BusinessException;
|
||||
import com.yolo.keyborad.model.dto.PageDTO;
|
||||
import com.yolo.keyborad.model.dto.companion.CompanionLikeReq;
|
||||
import com.yolo.keyborad.model.vo.AiCompanionVO;
|
||||
import com.yolo.keyborad.service.KeyboardAiCompanionLikeService;
|
||||
import com.yolo.keyborad.service.KeyboardAiCompanionService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -25,10 +30,25 @@ public class AiCompanionController {
|
||||
@Resource
|
||||
private KeyboardAiCompanionService aiCompanionService;
|
||||
|
||||
@Resource
|
||||
private KeyboardAiCompanionLikeService aiCompanionLikeService;
|
||||
|
||||
@PostMapping("/page")
|
||||
@Operation(summary = "分页查询AI陪聊角色", description = "分页查询已上线的AI陪聊角色列表")
|
||||
public BaseResponse<IPage<AiCompanionVO>> pageList(@RequestBody PageDTO pageDTO) {
|
||||
IPage<AiCompanionVO> result = aiCompanionService.pageList(pageDTO.getPageNum(), pageDTO.getPageSize());
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
|
||||
@PostMapping("/like")
|
||||
@Operation(summary = "点赞/取消点赞AI角色", description = "对AI角色进行点赞或取消点赞操作,返回true表示点赞成功,false表示取消点赞成功")
|
||||
public BaseResponse<Boolean> toggleLike(@RequestBody CompanionLikeReq req) {
|
||||
if (req.getCompanionId() == null) {
|
||||
throw new BusinessException(ErrorCode.COMPANION_ID_EMPTY);
|
||||
}
|
||||
|
||||
Long userId = StpUtil.getLoginIdAsLong();
|
||||
boolean result = aiCompanionLikeService.toggleLike(userId, req.getCompanionId());
|
||||
return ResultUtils.success(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.yolo.keyborad.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.yolo.keyborad.model.entity.KeyboardAiCompanionLike;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/1/27 18:18
|
||||
*/
|
||||
|
||||
public interface KeyboardAiCompanionLikeMapper extends BaseMapper<KeyboardAiCompanionLike> {
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.yolo.keyborad.model.dto.companion;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/1/27
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "AI角色点赞请求")
|
||||
public class CompanionLikeReq {
|
||||
|
||||
@Schema(description = "AI角色ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long companionId;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.yolo.keyborad.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/1/27 18:18
|
||||
*/
|
||||
|
||||
/**
|
||||
* 用户对AI陪伴角色的点赞行为记录表,用于记录点赞与取消点赞
|
||||
*/
|
||||
@Schema(description="用户对AI陪伴角色的点赞行为记录表,用于记录点赞与取消点赞")
|
||||
@Data
|
||||
@TableName(value = "keyboard_ai_companion_like")
|
||||
public class KeyboardAiCompanionLike {
|
||||
/**
|
||||
* AI角色点赞记录唯一ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@Schema(description="AI角色点赞记录唯一ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 被点赞的AI陪伴角色ID
|
||||
*/
|
||||
@TableField(value = "companion_id")
|
||||
@Schema(description="被点赞的AI陪伴角色ID")
|
||||
private Long companionId;
|
||||
|
||||
/**
|
||||
* 执行点赞操作的用户ID
|
||||
*/
|
||||
@TableField(value = "user_id")
|
||||
@Schema(description="执行点赞操作的用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 点赞状态:1=已点赞,0=已取消
|
||||
*/
|
||||
@TableField(value = "\"status\"")
|
||||
@Schema(description="点赞状态:1=已点赞,0=已取消")
|
||||
private Short status;
|
||||
|
||||
/**
|
||||
* 首次点赞时间
|
||||
*/
|
||||
@TableField(value = "created_at")
|
||||
@Schema(description="首次点赞时间")
|
||||
private Date createdAt;
|
||||
|
||||
/**
|
||||
* 点赞状态最近更新时间
|
||||
*/
|
||||
@TableField(value = "updated_at")
|
||||
@Schema(description="点赞状态最近更新时间")
|
||||
private Date updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.yolo.keyborad.service;
|
||||
|
||||
import com.yolo.keyborad.model.entity.KeyboardAiCompanionLike;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/1/27 18:18
|
||||
*/
|
||||
public interface KeyboardAiCompanionLikeService extends IService<KeyboardAiCompanionLike> {
|
||||
|
||||
/**
|
||||
* 点赞/取消点赞AI角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param companionId AI角色ID
|
||||
* @return true=点赞成功,false=取消点赞成功
|
||||
*/
|
||||
boolean toggleLike(Long userId, Long companionId);
|
||||
|
||||
/**
|
||||
* 检查用户是否已点赞某AI角色
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param companionId AI角色ID
|
||||
* @return true=已点赞,false=未点赞
|
||||
*/
|
||||
boolean hasLiked(Long userId, Long companionId);
|
||||
|
||||
/**
|
||||
* 批量获取用户已点赞的AI角色ID列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param companionIds AI角色ID列表
|
||||
* @return 已点赞的AI角色ID集合
|
||||
*/
|
||||
Set<Long> getLikedCompanionIds(Long userId, List<Long> companionIds);
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.yolo.keyborad.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.yolo.keyborad.common.ErrorCode;
|
||||
import com.yolo.keyborad.exception.BusinessException;
|
||||
import com.yolo.keyborad.mapper.KeyboardAiCompanionLikeMapper;
|
||||
import com.yolo.keyborad.mapper.KeyboardAiCompanionMapper;
|
||||
import com.yolo.keyborad.model.entity.KeyboardAiCompanion;
|
||||
import com.yolo.keyborad.model.entity.KeyboardAiCompanionLike;
|
||||
import com.yolo.keyborad.service.KeyboardAiCompanionLikeService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* @author: ziin
|
||||
* @date: 2026/1/27 18:18
|
||||
*/
|
||||
@Service
|
||||
public class KeyboardAiCompanionLikeServiceImpl extends ServiceImpl<KeyboardAiCompanionLikeMapper, KeyboardAiCompanionLike> implements KeyboardAiCompanionLikeService {
|
||||
|
||||
@Resource
|
||||
private KeyboardAiCompanionMapper companionMapper;
|
||||
|
||||
@Override
|
||||
public boolean hasLiked(Long userId, Long companionId) {
|
||||
LambdaQueryWrapper<KeyboardAiCompanionLike> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(KeyboardAiCompanionLike::getUserId, userId)
|
||||
.eq(KeyboardAiCompanionLike::getCompanionId, companionId)
|
||||
.eq(KeyboardAiCompanionLike::getStatus, (short) 1);
|
||||
return this.count(queryWrapper) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Long> getLikedCompanionIds(Long userId, List<Long> companionIds) {
|
||||
if (companionIds == null || companionIds.isEmpty()) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
LambdaQueryWrapper<KeyboardAiCompanionLike> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(KeyboardAiCompanionLike::getUserId, userId)
|
||||
.in(KeyboardAiCompanionLike::getCompanionId, companionIds)
|
||||
.eq(KeyboardAiCompanionLike::getStatus, (short) 1);
|
||||
List<KeyboardAiCompanionLike> likes = this.list(queryWrapper);
|
||||
return likes.stream()
|
||||
.map(KeyboardAiCompanionLike::getCompanionId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean toggleLike(Long userId, Long companionId) {
|
||||
// 检查AI角色是否存在
|
||||
KeyboardAiCompanion companion = companionMapper.selectById(companionId);
|
||||
if (companion == null || companion.getStatus() != 1) {
|
||||
throw new BusinessException(ErrorCode.COMPANION_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 查找现有点赞记录
|
||||
LambdaQueryWrapper<KeyboardAiCompanionLike> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(KeyboardAiCompanionLike::getUserId, userId)
|
||||
.eq(KeyboardAiCompanionLike::getCompanionId, companionId);
|
||||
KeyboardAiCompanionLike existingLike = this.getOne(queryWrapper);
|
||||
|
||||
Date now = new Date();
|
||||
boolean isLiked;
|
||||
|
||||
if (existingLike != null) {
|
||||
// 切换点赞状态
|
||||
if (existingLike.getStatus() == 1) {
|
||||
// 取消点赞
|
||||
existingLike.setStatus((short) 0);
|
||||
existingLike.setUpdatedAt(now);
|
||||
this.updateById(existingLike);
|
||||
isLiked = false;
|
||||
} else {
|
||||
// 重新点赞
|
||||
existingLike.setStatus((short) 1);
|
||||
existingLike.setUpdatedAt(now);
|
||||
this.updateById(existingLike);
|
||||
isLiked = true;
|
||||
}
|
||||
} else {
|
||||
// 新增点赞记录
|
||||
KeyboardAiCompanionLike like = new KeyboardAiCompanionLike();
|
||||
like.setUserId(userId);
|
||||
like.setCompanionId(companionId);
|
||||
like.setStatus((short) 1);
|
||||
like.setCreatedAt(now);
|
||||
like.setUpdatedAt(now);
|
||||
this.save(like);
|
||||
isLiked = true;
|
||||
}
|
||||
|
||||
return isLiked;
|
||||
}
|
||||
}
|
||||
18
src/main/resources/mapper/KeyboardAiCompanionLikeMapper.xml
Normal file
18
src/main/resources/mapper/KeyboardAiCompanionLikeMapper.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.yolo.keyborad.mapper.KeyboardAiCompanionLikeMapper">
|
||||
<resultMap id="BaseResultMap" type="com.yolo.keyborad.model.entity.KeyboardAiCompanionLike">
|
||||
<!--@mbg.generated-->
|
||||
<!--@Table keyboard_ai_companion_like-->
|
||||
<id column="id" jdbcType="BIGINT" property="id" />
|
||||
<result column="companion_id" jdbcType="BIGINT" property="companionId" />
|
||||
<result column="user_id" jdbcType="BIGINT" property="userId" />
|
||||
<result column="status" jdbcType="SMALLINT" property="status" />
|
||||
<result column="created_at" jdbcType="TIMESTAMP" property="createdAt" />
|
||||
<result column="updated_at" jdbcType="TIMESTAMP" property="updatedAt" />
|
||||
</resultMap>
|
||||
<sql id="Base_Column_List">
|
||||
<!--@mbg.generated-->
|
||||
id, companion_id, user_id, "status", created_at, updated_at
|
||||
</sql>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user