|
|
@@ -8,20 +8,19 @@ 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.LifeFeedbackReply;
|
|
|
import shop.alien.entity.store.LifeImg;
|
|
|
import shop.alien.entity.store.LifeLog;
|
|
|
-import shop.alien.entity.store.dto.LifeFeedbackDto;
|
|
|
-import shop.alien.entity.store.dto.UserReplyDto;
|
|
|
-import shop.alien.entity.store.vo.LifeFeedbackVo;
|
|
|
+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.LifeFeedbackReplyService;
|
|
|
import shop.alien.store.service.LifeImgService;
|
|
|
-import org.springframework.util.CollectionUtils;
|
|
|
|
|
|
import java.util.Date;
|
|
|
import java.util.List;
|
|
|
@@ -78,12 +77,12 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
|
|
|
List<LifeImg> fileList = new ArrayList<>();
|
|
|
// 收集所有视频的截图URL,避免重复保存为普通图片
|
|
|
List<String> videoThumbnailUrls = new ArrayList<>();
|
|
|
-
|
|
|
+
|
|
|
if (!CollectionUtils.isEmpty(dto.getFileUrlList())) {
|
|
|
// 先处理视频,找到所有视频及其封面图
|
|
|
List<String> videoUrls = new ArrayList<>();
|
|
|
List<String> imageUrls = new ArrayList<>();
|
|
|
-
|
|
|
+
|
|
|
// 分类:区分视频和图片
|
|
|
for (String fileUrl : dto.getFileUrlList()) {
|
|
|
if (isVideoUrl(fileUrl)) {
|
|
|
@@ -92,7 +91,7 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
|
|
|
imageUrls.add(fileUrl);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 处理视频:自动匹配封面图
|
|
|
for (String videoUrl : videoUrls) {
|
|
|
LifeImg video = new LifeImg();
|
|
|
@@ -100,13 +99,13 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
|
|
|
video.setImgUrl(videoUrl);
|
|
|
video.setFileType(2); // 2-视频
|
|
|
video.setUploadTime(new Date());
|
|
|
-
|
|
|
+
|
|
|
// 从fileUrlList中查找对应的封面图URL(通过文件名匹配)
|
|
|
// 视频URL格式: .../video/xxx123456.mp4
|
|
|
// 封面图URL格式: .../video/xxx123456.jpg 或 .../image/xxx123456.jpg
|
|
|
String videoFileName = videoUrl.substring(videoUrl.lastIndexOf('/') + 1);
|
|
|
String videoNameWithoutExt = videoFileName.substring(0, videoFileName.lastIndexOf('.'));
|
|
|
-
|
|
|
+
|
|
|
// 在图片列表中查找匹配的封面图
|
|
|
for (String imgUrl : imageUrls) {
|
|
|
String imgFileName = imgUrl.substring(imgUrl.lastIndexOf('/') + 1);
|
|
|
@@ -120,10 +119,10 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
fileList.add(video);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 处理图片(排除已作为视频封面的URL)
|
|
|
for (String imgUrl : imageUrls) {
|
|
|
// 如果该URL已被用作视频封面,则跳过,不重复保存
|
|
|
@@ -137,7 +136,7 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (!fileList.isEmpty()) {
|
|
|
lifeImgService.batchSave(fileList);
|
|
|
}
|
|
|
@@ -220,7 +219,7 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
|
|
|
isOriginalFeedback = false;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (isOriginalFeedback) {
|
|
|
if (img.getFileType() == 1) {
|
|
|
imgUrls.add(img.getImgUrl());
|
|
|
@@ -387,13 +386,13 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
|
|
|
return false;
|
|
|
}
|
|
|
String lowerUrl = url.toLowerCase();
|
|
|
- return lowerUrl.endsWith(".mp4") ||
|
|
|
- lowerUrl.endsWith(".avi") ||
|
|
|
- lowerUrl.endsWith(".flv") ||
|
|
|
- lowerUrl.endsWith(".mkv") ||
|
|
|
- lowerUrl.endsWith(".rmvb") ||
|
|
|
- lowerUrl.endsWith(".wmv") ||
|
|
|
- lowerUrl.endsWith(".3gp") ||
|
|
|
+ return lowerUrl.endsWith(".mp4") ||
|
|
|
+ lowerUrl.endsWith(".avi") ||
|
|
|
+ lowerUrl.endsWith(".flv") ||
|
|
|
+ lowerUrl.endsWith(".mkv") ||
|
|
|
+ lowerUrl.endsWith(".rmvb") ||
|
|
|
+ lowerUrl.endsWith(".wmv") ||
|
|
|
+ lowerUrl.endsWith(".3gp") ||
|
|
|
lowerUrl.endsWith(".mov");
|
|
|
}
|
|
|
|
|
|
@@ -407,14 +406,152 @@ public class LifeFeedbackServiceImpl extends ServiceImpl<LifeFeedbackMapper, Lif
|
|
|
return false;
|
|
|
}
|
|
|
String lowerUrl = url.toLowerCase();
|
|
|
- return lowerUrl.endsWith(".jpg") ||
|
|
|
- lowerUrl.endsWith(".jpeg") ||
|
|
|
- lowerUrl.endsWith(".png") ||
|
|
|
- lowerUrl.endsWith(".bmp") ||
|
|
|
- lowerUrl.endsWith(".webp") ||
|
|
|
- lowerUrl.endsWith(".gif") ||
|
|
|
+ return lowerUrl.endsWith(".jpg") ||
|
|
|
+ lowerUrl.endsWith(".jpeg") ||
|
|
|
+ lowerUrl.endsWith(".png") ||
|
|
|
+ lowerUrl.endsWith(".bmp") ||
|
|
|
+ lowerUrl.endsWith(".webp") ||
|
|
|
+ lowerUrl.endsWith(".gif") ||
|
|
|
lowerUrl.endsWith(".svg");
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ // ==================== 中台接口实现 ====================
|
|
|
+
|
|
|
+ @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);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|