优化评论返回模型,注意数据库表变更,需要重新运行sql脚本。完成评论和帖子的自定义热度排序

main
forely 4 weeks ago
parent d97a5a0b31
commit b626045de2

@ -3,9 +3,15 @@ package com.luojia_channel.modules.feedback.controller;
import com.luojia_channel.common.domain.Result; import com.luojia_channel.common.domain.Result;
import com.luojia_channel.common.domain.page.PageRequest; import com.luojia_channel.common.domain.page.PageRequest;
import com.luojia_channel.common.domain.page.PageResponse; import com.luojia_channel.common.domain.page.PageResponse;
import com.luojia_channel.common.exception.UserException;
import com.luojia_channel.common.utils.UserContext;
import com.luojia_channel.modules.feedback.dto.FeedbackTicketBasicInfoDTO;
import com.luojia_channel.modules.feedback.dto.FeedbackTicketPageQueryDTO;
import com.luojia_channel.modules.feedback.entity.FeedbackTicket; import com.luojia_channel.modules.feedback.entity.FeedbackTicket;
import com.luojia_channel.modules.feedback.service.FeedbackTicketService; import com.luojia_channel.modules.feedback.service.FeedbackTicketService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -35,17 +41,25 @@ public class FeedbackTicketController {
return Result.success(); return Result.success();
} }
@GetMapping("/personal") @GetMapping("/of/me")
@Operation(summary = "个人反馈工单查询", description = "查询当前用户的反馈工单") @Operation(summary = "个人反馈工单查询", description = "查询当前用户的反馈工单")
public Result<List<FeedbackTicket>> getPersonalFeedbackTickets(@RequestParam Long userId) { public Result<List<FeedbackTicket>> getPersonalFeedbackTickets() {
Long userId = UserContext.getUserId();
if(userId == null){
throw new UserException("用户未登录");
}
List<FeedbackTicket> tickets = feedbackTicketService.getPersonalFeedbackTickets(userId); List<FeedbackTicket> tickets = feedbackTicketService.getPersonalFeedbackTickets(userId);
return Result.success(tickets); return Result.success(tickets);
} }
@GetMapping("/admin") @GetMapping("/list")
@Operation(summary = "管理员反馈工单分页查询", description = "管理员分页查询所有反馈工单") @Operation(summary = "分页查询反馈工单", description = "分页查询反馈工单列表")
public Result<PageResponse<FeedbackTicket>> getAdminFeedbackTickets(PageRequest request) { @ApiResponses(value = {
PageResponse<FeedbackTicket> pageResponse = feedbackTicketService.getAdminFeedbackTickets(request); @ApiResponse(responseCode = "200", description = "获取成功"),
@ApiResponse(responseCode = "500", description = "获取失败,请稍后重试")
})
public Result<PageResponse<FeedbackTicketBasicInfoDTO>> pageFeedbackTicket(FeedbackTicketPageQueryDTO feedbackTicketPageQueryDTO) {
PageResponse<FeedbackTicketBasicInfoDTO> pageResponse = feedbackTicketService.pageFeedbackTicket(feedbackTicketPageQueryDTO);
return Result.success(pageResponse); return Result.success(pageResponse);
} }
} }

@ -1,2 +1,40 @@
package com.luojia_channel.modules.feedback.dto;public class FeedbackTicketBasicInfoDTO { package com.luojia_channel.modules.feedback.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Schema(description = "反馈工单基本信息")
public class FeedbackTicketBasicInfoDTO {
@Schema(description = "主键ID")
private Long id;
@Schema(description = "用户ID")
private Long userId;
@Schema(description = "反馈内容")
private String content;
@Schema(description = "反馈类型,例如:功能建议、问题反馈等")
private String feedbackType;
@Schema(description = "工单状态1:待处理2:处理中3:已处理")
private Integer status;
@Schema(description = "联系方式,如手机号、邮箱等")
private String contactInfo;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "处理时间")
private LocalDateTime handleTime;
@Schema(description = "用户名")
private String userName;
@Schema(description = "用户头像")
private String userAvatar;
} }

@ -1,2 +1,14 @@
package com.luojia_channel.modules.feedback.dto;public class FeedbackTicketPageQueryDTO { package com.luojia_channel.modules.feedback.dto;
import com.luojia_channel.common.domain.page.PageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class FeedbackTicketPageQueryDTO extends PageRequest {
@Schema(description = "反馈类型,例如:功能建议、问题反馈等")
private String feedbackType;
@Schema(description = "工单状态1:待处理2:处理中3:已处理")
private Integer status;
} }

@ -1,2 +1,23 @@
package com.luojia_channel.modules.feedback.entity;public class FeedbackTicket { package com.luojia_channel.modules.feedback.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("feedback_ticket")
public class FeedbackTicket {
@TableId(type = IdType.AUTO)
private Long id;
private Long userId;
private String content;
private String feedbackType;
private Integer status;
private String contactInfo;
private LocalDateTime createTime;
private LocalDateTime handleTime;
} }

@ -23,7 +23,7 @@ public class FeedbackMessageConsumer {
FeedbackTicket ticket = wrapper.getMessage(); FeedbackTicket ticket = wrapper.getMessage();
log.info("收到反馈工单延时消息工单ID{}", ticket.getId()); log.info("收到反馈工单延时消息工单ID{}", ticket.getId());
// 处理延时任务,例如更新工单状态 // 处理延时任务,更新工单状态
feedbackTicketService.processDelayedFeedback(ticket.getId()); feedbackTicketService.processDelayedFeedback(ticket.getId());
} catch (Exception e) { } catch (Exception e) {

@ -1,2 +1,13 @@
package com.luojia_channel.modules.feedback.mq.domain;public class DelayHandleTicketMessage { package com.luojia_channel.modules.feedback.mq.domain;
import lombok.Data;
@Data
public class DelayHandleTicketMessage {
private Long id;
private Long userId;
private String content;
private String feedbackType;
private Integer status;
private String contactInfo;
} }

@ -2,46 +2,33 @@ package com.luojia_channel.modules.feedback.mq.producer;
import com.luojia_channel.modules.feedback.config.FeedbackRabbitMQConfig; import com.luojia_channel.modules.feedback.config.FeedbackRabbitMQConfig;
import com.luojia_channel.modules.feedback.entity.FeedbackTicket; import com.luojia_channel.modules.feedback.mq.domain.DelayHandleTicketMessage;
import com.luojia_channel.modules.message.mq.AbstractSendProduceTemplate; import com.luojia_channel.modules.message.mq.AbstractSendProduceTemplate;
import com.luojia_channel.modules.message.mq.BaseSendExtendDTO;
import com.luojia_channel.modules.message.mq.MessageWrapper; import com.luojia_channel.modules.message.mq.MessageWrapper;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Slf4j @Slf4j
@Component @Component
@RequiredArgsConstructor public class FeedbackMessageProducer extends AbstractSendProduceTemplate<DelayHandleTicketMessage>{
public class FeedbackMessageProducer {
private final RabbitTemplate rabbitTemplate;
public void sendDelayMessage(FeedbackTicket ticket, Long delayTime) { public FeedbackMessageProducer(@Autowired RabbitTemplate rabbitTemplate){
try { super(rabbitTemplate);
// 构建消息包装器 }
MessageWrapper<FeedbackTicket> wrapper = MessageWrapper.<FeedbackTicket>builder()
.keys("feedback_" + ticket.getId())
.message(ticket)
.build();
// 发送消息到延迟队列设置消息TTL过期时间
rabbitTemplate.convertAndSend(
FeedbackRabbitMQConfig.FEEDBACK_EXCHANGE,
FeedbackRabbitMQConfig.FEEDBACK_ROUTING_KEY,
wrapper,
message -> {
message.getMessageProperties().setExpiration(delayTime.toString());
return message;
}
);
log.info("反馈工单延时消息发送成功工单ID{},延迟时间:{}ms", @Override
ticket.getId(), delayTime); protected BaseSendExtendDTO buildBaseSendParam(DelayHandleTicketMessage messageSendEvent) {
} catch (Exception e) { return BaseSendExtendDTO.builder()
log.error("反馈工单延时消息发送失败工单ID{}", ticket.getId(), e); .eventName("DelayHandleTicketMessageEvent")
throw e; .exchange(FeedbackRabbitMQConfig.FEEDBACK_EXCHANGE)
} .routingKey(FeedbackRabbitMQConfig.FEEDBACK_ROUTING_KEY)
.keys(messageSendEvent.getId().toString())
.delay(24*60*60*1000L) //延迟消息是1天
.build();
} }
} }

@ -1,6 +1,8 @@
package com.luojia_channel.modules.feedback.service; package com.luojia_channel.modules.feedback.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.luojia_channel.modules.feedback.dto.FeedbackTicketBasicInfoDTO;
import com.luojia_channel.modules.feedback.dto.FeedbackTicketPageQueryDTO;
import com.luojia_channel.modules.feedback.entity.FeedbackTicket; import com.luojia_channel.modules.feedback.entity.FeedbackTicket;
import com.luojia_channel.common.domain.page.PageRequest; import com.luojia_channel.common.domain.page.PageRequest;
import com.luojia_channel.common.domain.page.PageResponse; import com.luojia_channel.common.domain.page.PageResponse;
@ -29,9 +31,15 @@ public interface FeedbackTicketService extends IService<FeedbackTicket> {
List<FeedbackTicket> getPersonalFeedbackTickets(Long userId); List<FeedbackTicket> getPersonalFeedbackTickets(Long userId);
/** /**
* *
* @param request * @param feedbackTicketPageQueryDTO
* @return * @return
*/ */
PageResponse<FeedbackTicket> getAdminFeedbackTickets(PageRequest request); PageResponse<FeedbackTicketBasicInfoDTO> pageFeedbackTicket(FeedbackTicketPageQueryDTO feedbackTicketPageQueryDTO);
/**
*
* @param ticketId ID
*/
void processDelayedFeedback(Long ticketId);
} }

@ -1,2 +1,111 @@
package com.luojia_channel.modules.feedback.service.impl;public class FeedbackTicketServiceImpl { package com.luojia_channel.modules.feedback.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luojia_channel.common.domain.page.PageRequest;
import com.luojia_channel.common.domain.page.PageResponse;
import com.luojia_channel.modules.feedback.dto.FeedbackTicketBasicInfoDTO;
import com.luojia_channel.modules.feedback.dto.FeedbackTicketPageQueryDTO;
import com.luojia_channel.modules.feedback.entity.FeedbackTicket;
import com.luojia_channel.modules.feedback.mapper.FeedbackTicketMapper;
import com.luojia_channel.modules.feedback.mq.domain.DelayHandleTicketMessage;
import com.luojia_channel.modules.feedback.mq.producer.FeedbackMessageProducer;
import com.luojia_channel.modules.feedback.service.FeedbackTicketService;
import com.luojia_channel.modules.user.entity.User;
import com.luojia_channel.modules.user.mapper.UserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class FeedbackTicketServiceImpl extends ServiceImpl<FeedbackTicketMapper, FeedbackTicket> implements FeedbackTicketService {
private final UserMapper userMapper;
private final FeedbackMessageProducer feedbackMessageProducer;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createFeedbackTicket(FeedbackTicket feedbackTicket) {
feedbackTicket.setCreateTime(LocalDateTime.now());
feedbackTicket.setStatus(1);
if(!save(feedbackTicket))
throw new RuntimeException("保存工单失败");
// 发送延时消息
feedbackMessageProducer.sendMessage(BeanUtil.copyProperties(feedbackTicket, DelayHandleTicketMessage.class));
return feedbackTicket.getId();
}
@Override
public void updateFeedbackTicket(FeedbackTicket feedbackTicket) {
updateById(feedbackTicket);
}
@Override
public List<FeedbackTicket> getPersonalFeedbackTickets(Long userId) {
LambdaQueryWrapper<FeedbackTicket> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(FeedbackTicket::getUserId, userId);
return list(queryWrapper);
}
@Override
public PageResponse<FeedbackTicketBasicInfoDTO> pageFeedbackTicket(FeedbackTicketPageQueryDTO feedbackTicketPageQueryDTO) {
LambdaQueryWrapper<FeedbackTicket> queryWrapper = new LambdaQueryWrapper<>();
if (feedbackTicketPageQueryDTO.getFeedbackType() != null) {
queryWrapper.eq(FeedbackTicket::getFeedbackType, feedbackTicketPageQueryDTO.getFeedbackType());
}
if (feedbackTicketPageQueryDTO.getStatus() != null) {
queryWrapper.eq(FeedbackTicket::getStatus, feedbackTicketPageQueryDTO.getStatus());
}
queryWrapper.orderByDesc(FeedbackTicket::getCreateTime);
Page<FeedbackTicket> page = new Page<>(feedbackTicketPageQueryDTO.getCurrent(), feedbackTicketPageQueryDTO.getSize());
IPage<FeedbackTicket> feedbackTicketPage = baseMapper.selectPage(page, queryWrapper);
List<Long> userIds = new ArrayList<>();
feedbackTicketPage.getRecords().forEach(ticket -> userIds.add(ticket.getUserId()));
List<User> users = userMapper.selectBatchIds(userIds);
Map<Long, User> userMap = users.stream()
.collect(Collectors.toMap(User::getId, user -> user));
List<FeedbackTicketBasicInfoDTO> feedbackTicketBasicInfoDTOS = new ArrayList<>();
feedbackTicketPage.getRecords().forEach(ticket -> {
FeedbackTicketBasicInfoDTO dto = new FeedbackTicketBasicInfoDTO();
BeanUtil.copyProperties(ticket, dto);
User user = userMap.getOrDefault(ticket.getUserId(), new User());
dto.setUserName(user.getUsername());
dto.setUserAvatar(user.getAvatar());
feedbackTicketBasicInfoDTOS.add(dto);
});
return PageResponse.<FeedbackTicketBasicInfoDTO>builder()
.current(feedbackTicketPage.getCurrent())
.size(feedbackTicketPage.getSize())
.total(feedbackTicketPage.getTotal())
.records(feedbackTicketBasicInfoDTOS)
.build();
}
@Override
public void processDelayedFeedback(Long ticketId) {
// 查询工单
FeedbackTicket ticket = getById(ticketId);
if (ticket == null || ticket.getStatus().equals(3)) {
return;
}
// 处理延时任务,更新工单状态为超时
ticket.setStatus(4); //
updateById(ticket);
// TODO 向管理员发送消息
}
} }

@ -29,9 +29,9 @@ public abstract class AbstractSendProduceTemplate<T> {
m -> { m -> {
// 设置消息头 // 设置消息头
m.getMessageProperties().setHeader(KEYS, baseSendDTO.getKeys()); m.getMessageProperties().setHeader(KEYS, baseSendDTO.getKeys());
// 设置消息属性(如延迟时间) TODO 若需要延迟消息,需安装延时插件 // 设置消息属性(如延迟时间)
if (baseSendDTO.getDelay() != null) { if (baseSendDTO.getDelay() != null) {
// m.getMessageProperties().setDelay(baseSendDTO.getDelay()); m.getMessageProperties().setExpiration(baseSendDTO.getDelay().toString());
} }
return m; return m;
} }

@ -79,5 +79,5 @@ public class CommentInfoDTO {
@Schema( @Schema(
description = "子评论列表" description = "子评论列表"
) )
private List<CommentInfoDTO> commentInfoDTOList; private List<CommentInfoDTO> commentInfoDTOList; //当前返回空
} }

@ -1,36 +1,36 @@
###本地开发环境 ##本地开发环境
#lj:
# db:
# host: 192.168.59.129
# password: Forely123!
# redis:
# host: 192.168.59.129
# port: 6379
# password: Forely123!
# rabbitmq:
# host: 192.168.59.129
# port: 5672
# username: admin
# password: Forely123!
# minio:
# endpoint: http://192.168.59.129:9000
# accessKey: forely
# secretKey: Forely123!
lj: lj:
db: db:
host: 192.168.125.128 host: 192.168.59.129
password: MySQL@5678 password: Forely123!
redis: redis:
host: 192.168.125.128 host: 192.168.59.129
port: 6379 port: 6379
password: Redis@9012 password: Forely123!
rabbitmq: rabbitmq:
host: 192.168.125.128 host: 192.168.59.129
port: 5672 port: 5672
username: rabbit_admin username: admin
password: Rabbit@3456 password: Forely123!
minio: minio:
endpoint: http://192.168.125.128:9000 endpoint: http://192.168.59.129:9000
accessKey: minio_admin accessKey: forely
secretKey: Minio@1234 secretKey: Forely123!
#lj:
# db:
# host: 192.168.125.128
# password: MySQL@5678
# redis:
# host: 192.168.125.128
# port: 6379
# password: Redis@9012
# rabbitmq:
# host: 192.168.125.128
# port: 5672
# username: rabbit_admin
# password: Rabbit@3456
# minio:
# endpoint: http://192.168.125.128:9000
# accessKey: minio_admin
# secretKey: Minio@1234

@ -177,3 +177,20 @@ CREATE TABLE `follow` (
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关注表'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='关注表';
## 反馈工单表
DROP TABLE IF EXISTS `feedback_ticket`;
CREATE TABLE `feedback_ticket` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`user_id` BIGINT NOT NULL COMMENT '用户ID',
`content` TEXT NOT NULL COMMENT '反馈内容',
`feedback_type` VARCHAR(50) NOT NULL COMMENT '反馈类型,例如:功能建议、问题反馈等',
`status` INT NOT NULL COMMENT '工单状态1:待处理2:处理中3:已处理4超时',
`contact_info` VARCHAR(100) COMMENT '联系方式,如手机号、邮箱等',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`handle_time` DATETIME COMMENT '处理时间',
INDEX idx_user_id (`user_id`),
INDEX idx_feedback_type (`feedback_type`),
INDEX idx_status (`status`),
INDEX idx_create_time (`create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='反馈工单表';

Loading…
Cancel
Save