|
|
@@ -0,0 +1,374 @@
|
|
|
+package shop.alien.store.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+import shop.alien.entity.result.R;
|
|
|
+import shop.alien.entity.store.LifeFeedback;
|
|
|
+import shop.alien.entity.store.LifeImg;
|
|
|
+import shop.alien.entity.store.LifeLog;
|
|
|
+import shop.alien.entity.store.dto.*;
|
|
|
+import shop.alien.entity.store.vo.*;
|
|
|
+import shop.alien.mapper.LifeFeedbackMapper;
|
|
|
+import shop.alien.mapper.LifeLogMapper;
|
|
|
+import shop.alien.store.service.LifeFeedbackService;
|
|
|
+import shop.alien.store.service.LifeImgService;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 意见反馈 Service实现类
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor
|
|
|
+@Transactional(rollbackFor = Exception.class)
|
|
|
+public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, LifeFeedback> implements LifeFeedbackService {
|
|
|
+
|
|
|
+ private final LifeFeedbackMapper lifeFeedbackMapper;
|
|
|
+ private final LifeImgService lifeImgService;
|
|
|
+ private final LifeLogMapper lifeLogMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<String> submitFeedback(LifeFeedbackDto dto) {
|
|
|
+ try {
|
|
|
+ // 1. 参数校验
|
|
|
+ if (dto.getUserId() == null) {
|
|
|
+ return R.fail("用户ID不能为空");
|
|
|
+ }
|
|
|
+ if (dto.getFeedbackSource() == null) {
|
|
|
+ return R.fail("反馈来源不能为空");
|
|
|
+ }
|
|
|
+ if (dto.getFeedbackType() == null) {
|
|
|
+ return R.fail("反馈类型不能为空");
|
|
|
+ }
|
|
|
+ if (dto.getContent() == null || dto.getContent().trim().isEmpty()) {
|
|
|
+ return R.fail("反馈内容不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 创建反馈记录(使用MyBatis Plus的save方法)
|
|
|
+ LifeFeedback feedback = new LifeFeedback();
|
|
|
+ BeanUtils.copyProperties(dto, feedback);
|
|
|
+ feedback.setFeedbackTime(new Date());
|
|
|
+ feedback.setHandleStatus(0); // 处理中
|
|
|
+ feedback.setCreateTime(new Date());
|
|
|
+
|
|
|
+ boolean saveResult = this.save(feedback);
|
|
|
+ if (!saveResult) {
|
|
|
+ return R.fail("提交反馈失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 保存附件图片(使用批量插入)
|
|
|
+ if (!CollectionUtils.isEmpty(dto.getImgUrlList())) {
|
|
|
+ List<LifeImg> imgList = new java.util.ArrayList<>();
|
|
|
+ for (String imgUrl : dto.getImgUrlList()) {
|
|
|
+ LifeImg img = new LifeImg();
|
|
|
+ img.setFeedbackId(feedback.getId());
|
|
|
+ img.setImgUrl(imgUrl);
|
|
|
+ img.setFileType(1); // 默认图片
|
|
|
+ img.setUploadTime(new Date());
|
|
|
+ img.setCreateTime(new Date());
|
|
|
+ img.setCreatedUserId(dto.getUserId());
|
|
|
+ imgList.add(img);
|
|
|
+ }
|
|
|
+ lifeImgService.batchSave(imgList);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 记录日志 - 创建反馈工单
|
|
|
+ saveFeedbackLog(feedback.getId(), 2, "商家主动反馈/AI识别");
|
|
|
+
|
|
|
+ return R.success("提交成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("提交反馈失败", e);
|
|
|
+ return R.fail("提交反馈失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<String> replyFeedback(FeedbackReplyDto dto) {
|
|
|
+ try {
|
|
|
+ // 1. 参数校验
|
|
|
+ if (dto.getFeedbackId() == null) {
|
|
|
+ return R.fail("反馈ID不能为空");
|
|
|
+ }
|
|
|
+ if (dto.getStaffId() == null) {
|
|
|
+ return R.fail("工作人员ID不能为空");
|
|
|
+ }
|
|
|
+ if (dto.getContent() == null || dto.getContent().trim().isEmpty()) {
|
|
|
+ return R.fail("回复内容不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询原始反馈
|
|
|
+ LifeFeedback originalFeedback = lifeFeedbackMapper.selectById(dto.getFeedbackId());
|
|
|
+ if (originalFeedback == null) {
|
|
|
+ return R.fail("反馈记录不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 创建平台回复记录(使用MyBatis Plus的save方法)
|
|
|
+ LifeFeedback reply = new LifeFeedback();
|
|
|
+ reply.setUserId(originalFeedback.getUserId());
|
|
|
+ reply.setFeedbackSource(originalFeedback.getFeedbackSource());
|
|
|
+ reply.setFeedbackWay(1); // 平台回复(AI识别方式)
|
|
|
+ reply.setFeedbackType(originalFeedback.getFeedbackType());
|
|
|
+ reply.setContent(dto.getContent());
|
|
|
+ reply.setFeedbackTime(new Date());
|
|
|
+ reply.setStaffId(dto.getStaffId());
|
|
|
+ reply.setHandleStatus(1); // 已解决
|
|
|
+ reply.setCreateTime(new Date());
|
|
|
+
|
|
|
+ boolean saveResult = this.save(reply);
|
|
|
+ if (!saveResult) {
|
|
|
+ return R.fail("回复失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 更新原始反馈的处理状态和跟进人员(使用MyBatis Plus的updateById方法)
|
|
|
+ LifeFeedback updateFeedback = new LifeFeedback();
|
|
|
+ updateFeedback.setId(dto.getFeedbackId());
|
|
|
+ updateFeedback.setHandleStatus(0); // 处理中
|
|
|
+ updateFeedback.setStaffId(dto.getStaffId());
|
|
|
+ updateFeedback.setUpdateTime(new Date());
|
|
|
+ this.updateById(updateFeedback);
|
|
|
+
|
|
|
+ // 5. 记录日志
|
|
|
+ saveLog("平台回复反馈,原始反馈ID:" + dto.getFeedbackId() + ",回复ID:" + reply.getId());
|
|
|
+
|
|
|
+ return R.success("回复成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("回复反馈失败", e);
|
|
|
+ return R.fail("回复反馈失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public IPage<LifeFeedbackVo> getFeedbackList(Integer userId, Integer feedbackSource, int page, int size) {
|
|
|
+ try {
|
|
|
+ // 使用自定义SQL查询(已包含工作人员名称)
|
|
|
+ Page<LifeFeedbackVo> pageParam = new Page<>(page, size);
|
|
|
+ IPage<LifeFeedbackVo> voPage = lifeFeedbackMapper.selectFeedbackListWithStaff(
|
|
|
+ pageParam, userId, feedbackSource, 1, null
|
|
|
+ );
|
|
|
+
|
|
|
+ // 为每条记录查询附件图片
|
|
|
+ voPage.getRecords().forEach(vo -> {
|
|
|
+ List<String> imgUrls = lifeImgService.getImgUrlsByFeedbackId(vo.getId());
|
|
|
+ vo.setImgUrlList(imgUrls);
|
|
|
+ });
|
|
|
+
|
|
|
+ return voPage;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询反馈列表失败", e);
|
|
|
+ return new Page<>(page, size);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<LifeFeedbackVo> getFeedbackDetail(Integer feedbackId) {
|
|
|
+ try {
|
|
|
+ // 1. 使用自定义SQL查询反馈详情(已包含工作人员名称)
|
|
|
+ LifeFeedbackVo vo = lifeFeedbackMapper.selectFeedbackDetail(feedbackId);
|
|
|
+ if (vo == null) {
|
|
|
+ return R.fail("反馈记录不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询附件图片
|
|
|
+ List<String> imgUrls = lifeImgService.getImgUrlsByFeedbackId(feedbackId);
|
|
|
+ vo.setImgUrlList(imgUrls);
|
|
|
+
|
|
|
+ // 3. 查询平台回复列表(如果是主动反馈)
|
|
|
+ if (vo.getFeedbackWay() == 1) {
|
|
|
+ List<LifeFeedbackVo> replyList = lifeFeedbackMapper.selectPlatformReplies(
|
|
|
+ vo.getUserId(), vo.getFeedbackSource(), vo.getFeedbackTime()
|
|
|
+ );
|
|
|
+ vo.setPlatformReplies(replyList);
|
|
|
+ }
|
|
|
+
|
|
|
+ return R.data(vo);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询反馈详情失败", e);
|
|
|
+ return R.fail("查询反馈详情失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<String> updateHandleStatus(Integer feedbackId, Integer handleStatus, Integer staffId) {
|
|
|
+ try {
|
|
|
+ // 使用MyBatis Plus的updateById方法
|
|
|
+ LifeFeedback feedback = new LifeFeedback();
|
|
|
+ feedback.setId(feedbackId);
|
|
|
+ feedback.setHandleStatus(handleStatus);
|
|
|
+ feedback.setStaffId(staffId);
|
|
|
+ feedback.setUpdateTime(new Date());
|
|
|
+
|
|
|
+ boolean result = this.updateById(feedback);
|
|
|
+ if (result) {
|
|
|
+ saveLog("更新反馈处理状态,反馈ID:" + feedbackId + ",状态:" + handleStatus);
|
|
|
+ return R.success("更新成功");
|
|
|
+ }
|
|
|
+ return R.fail("更新失败");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("更新反馈处理状态失败", e);
|
|
|
+ return R.fail("更新失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存操作日志
|
|
|
+ */
|
|
|
+ private void saveLog(String context) {
|
|
|
+ try {
|
|
|
+ LifeLog log = new LifeLog();
|
|
|
+ log.setContext(context);
|
|
|
+ log.setCreatedTime(new Date());
|
|
|
+ lifeLogMapper.insert(log);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("保存日志失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // ==================== 中台接口实现 ====================
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<IPage<LifeFeedbackListVo>> getWebFeedbackList(LifeFeedbackQueryDto queryDto) {
|
|
|
+ try {
|
|
|
+ Page<LifeFeedbackListVo> pageParam = new Page<>(queryDto.getPage(), queryDto.getSize());
|
|
|
+ IPage<LifeFeedbackListVo> result = lifeFeedbackMapper.selectWebFeedbackList(
|
|
|
+ pageParam,
|
|
|
+ queryDto.getFeedbackType(),
|
|
|
+ queryDto.getHandleStatus(),
|
|
|
+ queryDto.getFeedbackSource(),
|
|
|
+ queryDto.getFeedbackWay()
|
|
|
+ );
|
|
|
+ return R.data(result);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("中台-查询意见反馈列表失败", e);
|
|
|
+ return R.fail("查询失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public R<LifeFeedbackDetailVo> getWebFeedbackDetail(Integer feedbackId) {
|
|
|
+ try {
|
|
|
+ if (feedbackId == null) {
|
|
|
+ return R.fail("反馈ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 查询反馈详情
|
|
|
+ LifeFeedbackDetailVo detail = lifeFeedbackMapper.selectWebFeedbackDetail(feedbackId);
|
|
|
+ if (detail == null) {
|
|
|
+ return R.fail("反馈记录不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询附件列表(图片/视频)
|
|
|
+ List<FeedbackAttachmentVo> attachments = new ArrayList<>();
|
|
|
+ List<LifeImg> imgList = lifeImgService.getByFeedbackId(feedbackId);
|
|
|
+ if (!CollectionUtils.isEmpty(imgList)) {
|
|
|
+ for (LifeImg img : imgList) {
|
|
|
+ FeedbackAttachmentVo attachment = new FeedbackAttachmentVo();
|
|
|
+ attachment.setId(img.getId());
|
|
|
+ attachment.setFileType(img.getFileType() != null ? img.getFileType() : 1);
|
|
|
+ attachment.setFileUrl(img.getImgUrl());
|
|
|
+ attachment.setThumbnailUrl(img.getThumbnailUrl());
|
|
|
+ attachments.add(attachment);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ detail.setAttachments(attachments);
|
|
|
+
|
|
|
+ return R.data(detail);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("中台-查询反馈详情失败", e);
|
|
|
+ return R.fail("查询失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R<String> webReplyUser(LifeFeedbackReplyWebDto replyDto) {
|
|
|
+ try {
|
|
|
+ // 1. 参数校验
|
|
|
+ if (replyDto.getFeedbackId() == null) {
|
|
|
+ return R.fail("反馈ID不能为空");
|
|
|
+ }
|
|
|
+ if (replyDto.getContent() == null || replyDto.getContent().trim().isEmpty()) {
|
|
|
+ return R.fail("回复内容不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 查询原始反馈
|
|
|
+ LifeFeedback feedback = lifeFeedbackMapper.selectById(replyDto.getFeedbackId());
|
|
|
+ if (feedback == null) {
|
|
|
+ return R.fail("反馈记录不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 记录回复日志(类型3-回复用户)
|
|
|
+ String logContent = replyDto.getContent();
|
|
|
+ if (replyDto.getUserReply() != null && !replyDto.getUserReply().trim().isEmpty()) {
|
|
|
+ logContent = replyDto.getContent() + "||用户回复:" + replyDto.getUserReply();
|
|
|
+ }
|
|
|
+ saveFeedbackLog(replyDto.getFeedbackId(), 3, logContent);
|
|
|
+
|
|
|
+ return R.success("回复成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("中台-回复用户失败", e);
|
|
|
+ return R.fail("回复失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public R<String> updateWebFeedbackStatus(LifeFeedbackStatusDto statusDto) {
|
|
|
+ try {
|
|
|
+ // 1. 参数校验
|
|
|
+ if (statusDto.getFeedbackId() == null) {
|
|
|
+ return R.fail("反馈ID不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 更新状态为已解决
|
|
|
+ LifeFeedback updateFeedback = new LifeFeedback();
|
|
|
+ updateFeedback.setId(statusDto.getFeedbackId());
|
|
|
+ updateFeedback.setHandleStatus(1); // 已解决
|
|
|
+ updateFeedback.setUpdateTime(new Date());
|
|
|
+
|
|
|
+ boolean result = this.updateById(updateFeedback);
|
|
|
+ if (!result) {
|
|
|
+ return R.fail("更新失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 记录日志(类型0-问题解决状态)
|
|
|
+ String logContent = "问题已解决";
|
|
|
+ saveFeedbackLog(statusDto.getFeedbackId(), 0, logContent);
|
|
|
+
|
|
|
+ return R.success("更新成功");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("中台-更新反馈状态失败", e);
|
|
|
+ return R.fail("更新失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存反馈操作日志
|
|
|
+ * @param feedbackId 反馈ID
|
|
|
+ * @param type 操作类型:0-问题解决状态,1-分配跟踪人员,2-创建反馈工单,3-回复用户
|
|
|
+ * @param context 日志内容
|
|
|
+ */
|
|
|
+ private void saveFeedbackLog(Integer feedbackId, Integer type, String context) {
|
|
|
+ try {
|
|
|
+ LifeLog lifeLog = new LifeLog();
|
|
|
+ lifeLog.setFeedbackId(feedbackId);
|
|
|
+ lifeLog.setType(String.valueOf(type));
|
|
|
+ lifeLog.setContext(context);
|
|
|
+ lifeLog.setCreatedTime(new Date());
|
|
|
+ lifeLog.setDeleteFlag(0);
|
|
|
+ lifeLogMapper.insert(lifeLog);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("保存反馈日志失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|