合并bug修复
This commit is contained in:
parent
fb1b493fc5
commit
11bd48dedc
|
|
@ -0,0 +1,68 @@
|
|||
package com.zbkj.common.model.chat;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("eb_private_message_burn")
|
||||
@Entity
|
||||
@Table(name = "eb_private_message_burn", indexes = {
|
||||
@Index(name = "uk_message_id", columnList = "message_id", unique = true),
|
||||
@Index(name = "idx_conversation_id", columnList = "conversation_id"),
|
||||
@Index(name = "idx_burn_at", columnList = "burn_at")
|
||||
})
|
||||
@ApiModel(value = "PrivateMessageBurn对象", description = "阅后即焚消息状态")
|
||||
public class PrivateMessageBurn implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty(value = "ID")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "消息ID")
|
||||
@Column(name = "message_id", nullable = false)
|
||||
private Long messageId;
|
||||
|
||||
@ApiModelProperty(value = "会话ID")
|
||||
@Column(name = "conversation_id", nullable = false)
|
||||
private Long conversationId;
|
||||
|
||||
@ApiModelProperty(value = "销毁秒数")
|
||||
@Column(name = "burn_seconds")
|
||||
private Integer burnSeconds;
|
||||
|
||||
@ApiModelProperty(value = "首次查看时间")
|
||||
@Column(name = "viewed_at")
|
||||
private Date viewedAt;
|
||||
|
||||
@ApiModelProperty(value = "销毁时间")
|
||||
@Column(name = "burn_at")
|
||||
private Date burnAt;
|
||||
|
||||
@ApiModelProperty(value = "是否已销毁")
|
||||
@Column(name = "burned", columnDefinition = "TINYINT(1) DEFAULT 0")
|
||||
private Boolean burned;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
@Column(name = "create_time")
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty(value = "更新时间")
|
||||
@Column(name = "update_time")
|
||||
private Date updateTime;
|
||||
}
|
||||
|
|
@ -28,6 +28,9 @@ public class SendMessageRequest implements Serializable {
|
|||
@ApiModelProperty(value = "语音时长(可选)")
|
||||
private Integer duration;
|
||||
|
||||
@ApiModelProperty(value = "阅后即焚秒数(可选,仅messageType=burn_image时使用)")
|
||||
private Integer burnSeconds;
|
||||
|
||||
// 兼容旧字段
|
||||
public String getMessage() {
|
||||
return content;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
package com.zbkj.common.response;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@ApiModel(value = "BurnViewResponse对象", description = "阅后即焚图片查看响应")
|
||||
public class BurnViewResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty(value = "消息ID")
|
||||
private Long messageId;
|
||||
|
||||
@ApiModelProperty(value = "媒体URL(可为空,已销毁或无权限时不返回)")
|
||||
private String mediaUrl;
|
||||
|
||||
@ApiModelProperty(value = "销毁秒数")
|
||||
private Integer burnSeconds;
|
||||
|
||||
@ApiModelProperty(value = "首次查看时间戳(毫秒)")
|
||||
private Long viewedAt;
|
||||
|
||||
@ApiModelProperty(value = "销毁时间戳(毫秒)")
|
||||
private Long burnAt;
|
||||
|
||||
@ApiModelProperty(value = "是否已销毁")
|
||||
private Boolean burned;
|
||||
}
|
||||
|
|
@ -57,6 +57,18 @@ public class ChatMessageResponse implements Serializable {
|
|||
@ApiModelProperty(value = "语音时长(秒)")
|
||||
private Integer duration;
|
||||
|
||||
@ApiModelProperty(value = "阅后即焚秒数(仅messageType=burn_image时)")
|
||||
private Integer burnSeconds;
|
||||
|
||||
@ApiModelProperty(value = "首次查看时间戳(毫秒,仅messageType=burn_image时)")
|
||||
private Long viewedAt;
|
||||
|
||||
@ApiModelProperty(value = "销毁时间戳(毫秒,仅messageType=burn_image时)")
|
||||
private Long burnAt;
|
||||
|
||||
@ApiModelProperty(value = "是否已销毁(仅messageType=burn_image时)")
|
||||
private Boolean burned;
|
||||
|
||||
@ApiModelProperty(value = "是否已读")
|
||||
private Boolean isRead;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.zbkj.front.controller;
|
|||
|
||||
import com.zbkj.common.model.chat.Conversation;
|
||||
import com.zbkj.common.request.SendMessageRequest;
|
||||
import com.zbkj.common.response.BurnViewResponse;
|
||||
import com.zbkj.common.response.ChatMessageResponse;
|
||||
import com.zbkj.common.response.ConversationResponse;
|
||||
import com.zbkj.common.result.CommonResult;
|
||||
|
|
@ -157,4 +158,12 @@ public class ConversationController {
|
|||
Integer userId = userService.getUserIdException();
|
||||
return CommonResult.success(conversationService.recallMessage(id, userId));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查看阅后即焚图片(触发计时)")
|
||||
@ApiImplicitParam(name = "id", value = "消息ID", required = true)
|
||||
@PostMapping("/messages/{id}/burn/view")
|
||||
public CommonResult<BurnViewResponse> viewBurnImage(@PathVariable Long id) {
|
||||
Integer userId = userService.getUserIdException();
|
||||
return CommonResult.success(conversationService.viewBurnImage(id, userId));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package com.zbkj.service.dao;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.zbkj.common.model.chat.PrivateMessageBurn;
|
||||
|
||||
public interface PrivateMessageBurnDao extends BaseMapper<PrivateMessageBurn> {
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||
import com.zbkj.common.model.chat.Conversation;
|
||||
import com.zbkj.common.model.chat.PrivateMessage;
|
||||
import com.zbkj.common.request.SendMessageRequest;
|
||||
import com.zbkj.common.response.BurnViewResponse;
|
||||
import com.zbkj.common.response.ChatMessageResponse;
|
||||
import com.zbkj.common.response.ConversationResponse;
|
||||
|
||||
|
|
@ -78,4 +79,6 @@ public interface ConversationService extends IService<Conversation> {
|
|||
* 发送消息(带详细参数)
|
||||
*/
|
||||
PrivateMessage sendMessage(Long conversationId, Integer senderId, String messageType, String content, String mediaUrl);
|
||||
|
||||
BurnViewResponse viewBurnImage(Long messageId, Integer userId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,15 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||
import com.zbkj.common.exception.CrmebException;
|
||||
import com.zbkj.common.model.chat.Conversation;
|
||||
import com.zbkj.common.model.chat.PrivateMessage;
|
||||
import com.zbkj.common.model.chat.PrivateMessageBurn;
|
||||
import com.zbkj.common.model.user.User;
|
||||
import com.zbkj.common.request.SendMessageRequest;
|
||||
import com.zbkj.common.response.BurnViewResponse;
|
||||
import com.zbkj.common.response.ChatMessageResponse;
|
||||
import com.zbkj.common.response.ConversationResponse;
|
||||
import com.zbkj.service.dao.ConversationDao;
|
||||
import com.zbkj.service.dao.PrivateMessageDao;
|
||||
import com.zbkj.service.dao.PrivateMessageBurnDao;
|
||||
import com.zbkj.service.dao.UserBlacklistDao;
|
||||
import com.zbkj.service.service.ConversationService;
|
||||
import com.zbkj.service.service.OnlineStatusService;
|
||||
|
|
@ -36,6 +39,9 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationDao, Conver
|
|||
@Autowired
|
||||
private PrivateMessageDao privateMessageDao;
|
||||
|
||||
@Autowired
|
||||
private PrivateMessageBurnDao privateMessageBurnDao;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
|
|
@ -189,19 +195,35 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationDao, Conver
|
|||
// 检查黑名单状态
|
||||
checkBlacklistStatus(userId, receiverId);
|
||||
|
||||
String messageType = request.getMessageType() != null ? request.getMessageType() : "text";
|
||||
|
||||
// 获取消息内容(兼容新旧字段)
|
||||
String content = request.getContent() != null ? request.getContent() : request.getMessage();
|
||||
|
||||
// 文本消息要求 content 非空;媒体消息允许 content 为空
|
||||
if ("text".equals(messageType)) {
|
||||
if (content == null || content.trim().isEmpty()) {
|
||||
throw new CrmebException("消息内容不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
if ("burn_image".equals(messageType)) {
|
||||
if (request.getMediaUrl() == null || request.getMediaUrl().trim().isEmpty()) {
|
||||
throw new CrmebException("阅后图片mediaUrl不能为空");
|
||||
}
|
||||
Integer burnSeconds = request.getBurnSeconds();
|
||||
if (burnSeconds == null || !(burnSeconds == 3 || burnSeconds == 5 || burnSeconds == 10)) {
|
||||
throw new CrmebException("阅后即焚秒数仅支持3/5/10");
|
||||
}
|
||||
}
|
||||
|
||||
// 创建消息
|
||||
PrivateMessage message = new PrivateMessage();
|
||||
message.setConversationId(conversationId);
|
||||
message.setSenderId(userId);
|
||||
message.setReceiverId(receiverId);
|
||||
message.setContent(content);
|
||||
message.setMessageType(request.getMessageType() != null ? request.getMessageType() : "text");
|
||||
message.setContent(content != null ? content : "");
|
||||
message.setMessageType(messageType);
|
||||
message.setMediaUrl(request.getMediaUrl());
|
||||
message.setDuration(request.getDuration());
|
||||
message.setStatus("sent");
|
||||
|
|
@ -210,12 +232,25 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationDao, Conver
|
|||
message.setCreateTime(new Date());
|
||||
privateMessageDao.insert(message);
|
||||
|
||||
if ("burn_image".equals(messageType)) {
|
||||
PrivateMessageBurn burn = new PrivateMessageBurn();
|
||||
burn.setMessageId(message.getId());
|
||||
burn.setConversationId(conversationId);
|
||||
burn.setBurnSeconds(request.getBurnSeconds());
|
||||
burn.setBurned(false);
|
||||
burn.setCreateTime(new Date());
|
||||
burn.setUpdateTime(new Date());
|
||||
privateMessageBurnDao.insert(burn);
|
||||
}
|
||||
|
||||
// 更新会话的最后消息和时间
|
||||
String lastMessagePreview = content;
|
||||
if ("image".equals(message.getMessageType())) {
|
||||
lastMessagePreview = "[图片]";
|
||||
} else if ("voice".equals(message.getMessageType())) {
|
||||
lastMessagePreview = "[语音]";
|
||||
} else if ("burn_image".equals(message.getMessageType())) {
|
||||
lastMessagePreview = "[阅后图片]";
|
||||
}
|
||||
|
||||
LambdaUpdateWrapper<Conversation> uw = new LambdaUpdateWrapper<>();
|
||||
|
|
@ -236,6 +271,84 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationDao, Conver
|
|||
return convertMessageToResponse(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public BurnViewResponse viewBurnImage(Long messageId, Integer userId) {
|
||||
PrivateMessage message = privateMessageDao.selectById(messageId);
|
||||
if (message == null) {
|
||||
throw new CrmebException("消息不存在");
|
||||
}
|
||||
if (!"burn_image".equals(message.getMessageType())) {
|
||||
throw new CrmebException("消息类型不支持");
|
||||
}
|
||||
|
||||
Conversation conversation = getById(message.getConversationId());
|
||||
if (conversation == null ||
|
||||
(!conversation.getUser1Id().equals(userId) && !conversation.getUser2Id().equals(userId))) {
|
||||
throw new CrmebException("无权限查看此消息");
|
||||
}
|
||||
|
||||
PrivateMessageBurn burn = privateMessageBurnDao.selectOne(
|
||||
new LambdaQueryWrapper<PrivateMessageBurn>()
|
||||
.eq(PrivateMessageBurn::getMessageId, messageId)
|
||||
.last("LIMIT 1"));
|
||||
|
||||
if (burn == null) {
|
||||
throw new CrmebException("阅后状态不存在");
|
||||
}
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
boolean burned = Boolean.TRUE.equals(burn.getBurned());
|
||||
if (!burned && burn.getBurnAt() != null && burn.getBurnAt().getTime() <= now.getTime()) {
|
||||
burn.setBurned(true);
|
||||
burn.setUpdateTime(now);
|
||||
privateMessageBurnDao.updateById(burn);
|
||||
burned = true;
|
||||
}
|
||||
|
||||
BurnViewResponse resp = new BurnViewResponse();
|
||||
resp.setMessageId(messageId);
|
||||
resp.setBurnSeconds(burn.getBurnSeconds());
|
||||
resp.setViewedAt(burn.getViewedAt() != null ? burn.getViewedAt().getTime() : null);
|
||||
resp.setBurnAt(burn.getBurnAt() != null ? burn.getBurnAt().getTime() : null);
|
||||
resp.setBurned(burned);
|
||||
|
||||
if (burned) {
|
||||
resp.setMediaUrl(null);
|
||||
return resp;
|
||||
}
|
||||
|
||||
boolean isSender = message.getSenderId().equals(userId);
|
||||
boolean isReceiver = message.getReceiverId().equals(userId);
|
||||
|
||||
if (isReceiver) {
|
||||
if (burn.getViewedAt() == null) {
|
||||
burn.setViewedAt(now);
|
||||
long burnAtMs = now.getTime() + (burn.getBurnSeconds() != null ? burn.getBurnSeconds() : 0) * 1000L;
|
||||
burn.setBurnAt(new Date(burnAtMs));
|
||||
burn.setUpdateTime(now);
|
||||
privateMessageBurnDao.updateById(burn);
|
||||
|
||||
resp.setViewedAt(burn.getViewedAt().getTime());
|
||||
resp.setBurnAt(burn.getBurnAt().getTime());
|
||||
resp.setMediaUrl(message.getMediaUrl());
|
||||
} else {
|
||||
// 接收方只允许查看一次
|
||||
resp.setMediaUrl(null);
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
if (isSender) {
|
||||
resp.setMediaUrl(message.getMediaUrl());
|
||||
return resp;
|
||||
}
|
||||
|
||||
resp.setMediaUrl(null);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean deleteMessage(Long messageId, Integer userId) {
|
||||
|
|
@ -395,6 +508,26 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationDao, Conver
|
|||
return response;
|
||||
}
|
||||
|
||||
private void fillBurnFields(ChatMessageResponse response, Long messageId) {
|
||||
PrivateMessageBurn burn = privateMessageBurnDao.selectOne(
|
||||
new LambdaQueryWrapper<PrivateMessageBurn>()
|
||||
.eq(PrivateMessageBurn::getMessageId, messageId)
|
||||
.last("LIMIT 1"));
|
||||
if (burn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
response.setBurnSeconds(burn.getBurnSeconds());
|
||||
response.setViewedAt(burn.getViewedAt() != null ? burn.getViewedAt().getTime() : null);
|
||||
response.setBurnAt(burn.getBurnAt() != null ? burn.getBurnAt().getTime() : null);
|
||||
|
||||
boolean burned = Boolean.TRUE.equals(burn.getBurned());
|
||||
if (!burned && burn.getBurnAt() != null && burn.getBurnAt().getTime() <= System.currentTimeMillis()) {
|
||||
burned = true;
|
||||
}
|
||||
response.setBurned(burned);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换消息列表为响应对象列表
|
||||
*/
|
||||
|
|
@ -426,6 +559,11 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationDao, Conver
|
|||
response.setMediaUrl(message.getMediaUrl());
|
||||
response.setDuration(message.getDuration());
|
||||
|
||||
if ("burn_image".equals(message.getMessageType())) {
|
||||
response.setMediaUrl(null);
|
||||
fillBurnFields(response, message.getId());
|
||||
}
|
||||
|
||||
// 设置是否已读
|
||||
response.setIsRead("read".equals(message.getStatus()));
|
||||
|
||||
|
|
|
|||
15
Zhibo/zhibo-h/sql/create_private_message_burn_table.sql
Normal file
15
Zhibo/zhibo-h/sql/create_private_message_burn_table.sql
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
CREATE TABLE IF NOT EXISTS `eb_private_message_burn` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`message_id` BIGINT(20) NOT NULL COMMENT '消息ID',
|
||||
`conversation_id` BIGINT(20) NOT NULL COMMENT '会话ID',
|
||||
`burn_seconds` INT(11) DEFAULT NULL COMMENT '销毁秒数',
|
||||
`viewed_at` DATETIME DEFAULT NULL COMMENT '首次查看时间',
|
||||
`burn_at` DATETIME DEFAULT NULL COMMENT '销毁时间',
|
||||
`burned` TINYINT(1) DEFAULT 0 COMMENT '是否已销毁',
|
||||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_message_id` (`message_id`),
|
||||
KEY `idx_conversation_id` (`conversation_id`),
|
||||
KEY `idx_burn_at` (`burn_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='阅后即焚消息状态表';
|
||||
Loading…
Reference in New Issue
Block a user