Prechádzať zdrojové kódy

add 订单添加图片UI

tea 1 mesiac pred
rodič
commit
272855d3d5

+ 13 - 0
kxmall-admin-api/src/main/java/com/kxmall/web/controller/order/service/impl/KxStoreOrderServiceImpl.java

@@ -34,6 +34,7 @@ import com.kxmall.order.domain.bo.RiderProductBO;
 import com.kxmall.order.domain.vo.KxOrderStatisticalVo;
 import com.kxmall.order.domain.vo.KxStoreOrderProductVo;
 import com.kxmall.order.domain.vo.KxStoreOrderVo;
+import com.kxmall.order.domain.vo.KxOrderScreenshotVo;
 import com.kxmall.order.mapper.*;
 import com.kxmall.rider.domain.KxRider;
 import com.kxmall.rider.domain.vo.KxRiderVo;
@@ -98,6 +99,8 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
 
     private final KxStoreAfterSalesMapper storeAfterSalesMapper;
 
+    private final KxOrderScreenshotMapper orderScreenshotMapper;
+
     private final KxStoreAfterSalesItemMapper storeAfterSalesItemMapper;
 
     private final KxStoreAfterSalesStatusMapper storeAfterSalesStatusMapper;
@@ -138,6 +141,16 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
             kxStoreOrderVo.setRiderName(riderVo.getName());
         }
 
+        // 加载订单照片
+        List<KxOrderScreenshotVo> photos = orderScreenshotMapper.selectVoList(
+            new LambdaQueryWrapper<KxOrderScreenshot>()
+                .eq(KxOrderScreenshot::getOrderId, kxStoreOrderVo.getId())
+                .eq(KxOrderScreenshot::getIsDeleted, 0)
+                .orderByAsc(KxOrderScreenshot::getSortOrder)
+                .orderByAsc(KxOrderScreenshot::getCreateTime)
+        );
+        kxStoreOrderVo.setPhotos(photos);
+
         return kxStoreOrderVo;
     }
 

+ 9 - 0
kxmall-app-api/src/main/java/com/kxmall/web/controller/order/KxAppOrderScreenshotController.java

@@ -2,6 +2,7 @@ package com.kxmall.web.controller.order;
 
 import com.kxmall.common.core.controller.BaseAppController;
 import com.kxmall.common.core.domain.R;
+import com.kxmall.order.domain.bo.KxOrderScreenshotBo;
 import com.kxmall.order.domain.vo.KxOrderScreenshotVo;
 import com.kxmall.web.controller.order.service.IKxOrderScreenshotService;
 import lombok.RequiredArgsConstructor;
@@ -45,5 +46,13 @@ public class KxAppOrderScreenshotController extends BaseAppController {
         return R.ok(list);
     }
 
+    /**
+     * 添加订单照片
+     */
+    @PostMapping("/add")
+    public R<Void> add(@RequestBody KxOrderScreenshotBo bo) {
+        orderScreenshotService.add(bo);
+        return toAjax(true);
+    }
 
 }

+ 2 - 1
kxmall-app-api/src/main/java/com/kxmall/web/controller/order/builder/OrderConcreteBuilder.java

@@ -276,7 +276,8 @@ public class OrderConcreteBuilder extends OrderBuilder {
         OrderPriceBo orderPriceBo = new OrderPriceBo();
         orderPriceBo.setGroupShopId(groupShopId);
         orderPriceBo.setActualPrice(actualPrice);
-        orderPriceBo.setUrgentFee(orderRequest.getUrgentFee());
+        BigDecimal urgentFee = orderRequest.getUrgentFee() != null ? orderRequest.getUrgentFee() : BigDecimal.ZERO;
+        orderPriceBo.setUrgentFee(urgentFee);
         // 秒杀
         orderPriceBo.setSeckillId(seckillId);
         orderPriceBo.setFreightPrice(freightPrice);

+ 2 - 0
kxmall-app-api/src/main/java/com/kxmall/web/controller/order/service/IKxOrderScreenshotService.java

@@ -1,5 +1,6 @@
 package com.kxmall.web.controller.order.service;
 
+import com.kxmall.order.domain.bo.KxOrderScreenshotBo;
 import com.kxmall.order.domain.vo.KxOrderScreenshotVo;
 
 import java.util.List;
@@ -40,4 +41,5 @@ public interface IKxOrderScreenshotService {
      */
     List<KxOrderScreenshotVo> queryByOrderIdAndType(String orderId, Integer screenshotType, Integer userType);
 
+    void add(KxOrderScreenshotBo bo);
 }

+ 21 - 0
kxmall-app-api/src/main/java/com/kxmall/web/controller/order/service/impl/KxOrderScreenshotServiceImpl.java

@@ -3,6 +3,7 @@ package com.kxmall.web.controller.order.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.kxmall.common.utils.StringUtils;
 import com.kxmall.order.domain.KxOrderScreenshot;
+import com.kxmall.order.domain.bo.KxOrderScreenshotBo;
 import com.kxmall.order.domain.vo.KxOrderScreenshotVo;
 import com.kxmall.order.mapper.KxOrderScreenshotMapper;
 import com.kxmall.web.controller.order.service.IKxOrderScreenshotService;
@@ -126,4 +127,24 @@ public class KxOrderScreenshotServiceImpl implements IKxOrderScreenshotService {
         return baseMapper.selectVoList(lqw);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void add(KxOrderScreenshotBo bo) {
+        LocalDateTime now = LocalDateTime.now();
+        List<String> imageUrls = bo.getImageUrls();
+        for (int i = 0; i < imageUrls.size(); i++) {
+            String imageUrl = imageUrls.get(i);
+            KxOrderScreenshot screenshot = new KxOrderScreenshot();
+            screenshot.setOrderId(bo.getOrderId());
+            screenshot.setScreenshotType(bo.getScreenshotType());
+            screenshot.setImageUrl(imageUrl);
+            screenshot.setUserType(bo.getUserType());
+            screenshot.setUploadBy(bo.getUploadBy());
+            screenshot.setSortOrder(i + 1);
+            screenshot.setUploadTime(now);
+            screenshot.setCreateTime(now);
+            screenshot.setIsDeleted(0);
+            baseMapper.insert(screenshot);
+        }
+    }
 }

+ 27 - 0
kxmall-common/src/main/java/com/kxmall/common/utils/StreamUtil.java

@@ -0,0 +1,27 @@
+package com.kxmall.common.utils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author tea
+ * @date 2022/4/21
+ */
+public class StreamUtil {
+
+	public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
+		Map<Object, Boolean> seen = new ConcurrentHashMap<>();
+		return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
+	}
+
+	@SafeVarargs
+    public static <T> List<T> addAll(List<T> ... a) {
+		return Stream.of(a).flatMap(Collection::stream).collect(Collectors.toList());
+	}
+}

+ 23 - 40
kxmall-rider-api/src/main/java/com/kxmall/web/controller/rider/service/impl/RiderReviewServiceImpl.java

@@ -1,16 +1,21 @@
 package com.kxmall.web.controller.rider.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.kxmall.common.core.domain.PageQuery;
 import com.kxmall.common.core.page.TableDataInfo;
 import com.kxmall.common.exception.ServiceException;
+import com.kxmall.common.utils.StreamUtil;
 import com.kxmall.common.utils.StringUtils;
 import com.kxmall.order.domain.KxStoreAppraise;
 import com.kxmall.order.domain.bo.KxStoreAppraiseBo;
 import com.kxmall.order.domain.vo.KxStoreAppraiseVo;
 import com.kxmall.order.mapper.KxStoreAppraiseMapper;
+import com.kxmall.product.domain.KxStoreProduct;
+import com.kxmall.product.domain.vo.KxStoreProductVo;
+import com.kxmall.product.mapper.KxStoreProductMapper;
 import com.kxmall.rider.domain.KxRiderOrder;
 import com.kxmall.rider.mapper.KxRiderOrderMapper;
 import com.kxmall.web.controller.rider.service.RiderReviewService;
@@ -18,6 +23,7 @@ import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -36,6 +42,7 @@ public class RiderReviewServiceImpl implements RiderReviewService {
 
     private final KxStoreAppraiseMapper appraiseMapper;
     private final KxRiderOrderMapper riderOrderMapper;
+    private final KxStoreProductMapper kxStoreProductMapper;
 
     @Override
     public TableDataInfo<KxStoreAppraiseVo> queryPageList(KxStoreAppraiseBo bo, PageQuery pageQuery) {
@@ -47,7 +54,7 @@ public class RiderReviewServiceImpl implements RiderReviewService {
         }
 
         LambdaQueryWrapper<KxStoreAppraise> lqw = buildQueryWrapper(bo);
-        lqw.in(KxStoreAppraise::getOrderId, orderIds);
+        lqw.in(KxStoreAppraise::getOrderId, orderIds).eq(KxStoreAppraise::getState, 1);
         
         // 添加评分筛选条件
         if (bo.getMinRating() != null) {
@@ -60,6 +67,11 @@ public class RiderReviewServiceImpl implements RiderReviewService {
         lqw.orderByDesc(KxStoreAppraise::getCreateTime);
         
         Page<KxStoreAppraiseVo> result = appraiseMapper.selectVoPage(new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()), lqw);
+        if (CollUtil.isNotEmpty(result.getRecords())) {
+            List<Long> productIds = result.getRecords().stream().map(KxStoreAppraiseVo::getProductId).collect(Collectors.toList());
+            Map<Long, String> storeNameMap = kxStoreProductMapper.selectVoBatchIds(productIds).stream().collect(Collectors.toMap(KxStoreProductVo::getId, KxStoreProductVo::getStoreName, (old, newV) -> newV));
+            result.getRecords().forEach(appraise -> appraise.setProductName(storeNameMap.get(appraise.getProductId())));
+        }
         return TableDataInfo.build(result);
     }
 
@@ -83,16 +95,13 @@ public class RiderReviewServiceImpl implements RiderReviewService {
     @Override
     public Map<String, Object> getRiderReviewStats(Long riderId) {
         Map<String, Object> stats = new HashMap<>();
-        
+        stats.put("totalReviews", 0);
+        stats.put("averageRating", 0.0);
+
         // 获取该骑手配送的所有订单ID
         List<Long> orderIds = getRiderOrderIds(riderId);
         
         if (orderIds.isEmpty()) {
-            stats.put("totalReviews", 0);
-            stats.put("averageRating", 0.0);
-            stats.put("goodReviews", 0);
-            stats.put("mediumReviews", 0);
-            stats.put("badReviews", 0);
             return stats;
         }
 
@@ -102,40 +111,14 @@ public class RiderReviewServiceImpl implements RiderReviewService {
         
         List<KxStoreAppraise> appraises = appraiseMapper.selectList(lqw);
         
-        if (appraises.isEmpty()) {
-            stats.put("totalReviews", 0);
-            stats.put("averageRating", 0.0);
-            stats.put("goodReviews", 0);
-            stats.put("mediumReviews", 0);
-            stats.put("badReviews", 0);
-            return stats;
+        if (CollUtil.isNotEmpty(appraises)) {
+            long count = appraises.stream().filter(StreamUtil.distinctByKey(KxStoreAppraise::getOrderId)).count();
+            stats.put("totalReviews", count);
+            double sum = appraises.stream().mapToDouble(KxStoreAppraise::getScore).sum();
+            BigDecimal avg = BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP);
+            stats.put("averageRating", avg);
         }
-        
-        // 计算统计数据
-        int totalReviews = appraises.size();
-        double averageRating = appraises.stream()
-                .mapToLong(KxStoreAppraise::getScore)
-                .average()
-                .orElse(0.0);
-                
-        long goodReviews = appraises.stream()
-                .filter(a -> a.getScore() >= 4)
-                .count();
-                
-        long mediumReviews = appraises.stream()
-                .filter(a -> a.getScore() == 3)
-                .count();
-                
-        long badReviews = appraises.stream()
-                .filter(a -> a.getScore() <= 2)
-                .count();
-        
-        stats.put("totalReviews", totalReviews);
-        stats.put("averageRating", BigDecimal.valueOf(averageRating).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue());
-        stats.put("goodReviews", goodReviews);
-        stats.put("mediumReviews", mediumReviews);
-        stats.put("badReviews", badReviews);
-        
+
         return stats;
     }
 

+ 15 - 0
kxmall-rider-api/src/main/java/com/kxmall/web/controller/task/service/impl/TaskCenterServiceImpl.java

@@ -1,5 +1,6 @@
 package com.kxmall.web.controller.task.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.kxmall.common.core.domain.PageQuery;
@@ -10,6 +11,8 @@ import com.kxmall.common.enums.RiderTransactionType;
 import com.kxmall.common.exception.ServiceException;
 import com.kxmall.common.utils.redis.RedisUtils;
 import com.kxmall.order.biz.OrderRiderBizService;
+import com.kxmall.order.domain.KxOrderScreenshot;
+import com.kxmall.order.mapper.KxOrderScreenshotMapper;
 import com.kxmall.rider.domain.KxRider;
 import com.kxmall.rider.domain.KxRiderItem;
 import com.kxmall.rider.domain.KxRiderOrder;
@@ -35,6 +38,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
+import java.util.stream.Collectors;
 
 /**
  * @description: 配送中心业务接口
@@ -61,6 +65,9 @@ public class TaskCenterServiceImpl implements TaskCenterService {
     @Resource
     OrderRiderBizService orderRiderBizService;
 
+    @Resource
+    private KxOrderScreenshotMapper kxOrderScreenshotMapper;
+
 
     private static final Logger logger = LoggerFactory.getLogger(TaskCenterServiceImpl.class);
 
@@ -103,6 +110,14 @@ public class TaskCenterServiceImpl implements TaskCenterService {
         }
         KxRiderOrderVo riderOrderDTO = new KxRiderOrderVo();
         BeanUtils.copyProperties(riderOrderDO, riderOrderDTO);
+
+        LambdaQueryWrapper<KxOrderScreenshot> lqw = new LambdaQueryWrapper<>();
+        lqw.eq(KxOrderScreenshot::getOrderId, riderOrderDO.getOrderId()).eq(KxOrderScreenshot::getIsDeleted, 0);
+        Map<Integer, List<String>> imagesMap = kxOrderScreenshotMapper.selectList(lqw).stream()
+                .collect(Collectors.groupingBy(KxOrderScreenshot::getUserType, Collectors.mapping(KxOrderScreenshot::getImageUrl, Collectors.toList())));
+        riderOrderDTO.setUserImageUrls(imagesMap.get(1));
+        riderOrderDTO.setImageUrls(imagesMap.get(2));
+
         riderOrderDTO.setRiderItemVoList(riderSpuDOS);
         return riderOrderDTO;
     }

+ 42 - 0
kxmall-system/src/main/java/com/kxmall/order/domain/bo/KxOrderScreenshotBo.java

@@ -0,0 +1,42 @@
+package com.kxmall.order.domain.bo;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 订单截图视图对象 kx_order_screenshot
+ *
+ * @author kxmall
+ * @date 2024-12-01
+ */
+@Data
+public class KxOrderScreenshotBo {
+
+    /**
+     * 订单号
+     */
+    private String orderId;
+
+    /**
+     * (1:创建订单, 2:服务前, 3:服务中, 4:服务后, 5:问题反馈, 0:其他)
+     */
+    private Byte screenshotType;
+
+    /**
+     * 图片URL
+     */
+    private List<String> imageUrls;
+
+    /**
+     * 图片类型(1:用户、2:师傅、3:admin)
+     */
+    private Integer userType;
+
+    /**
+     * 上传人
+     */
+    private Long uploadBy;
+
+}

+ 6 - 0
kxmall-system/src/main/java/com/kxmall/order/domain/vo/KxStoreOrderVo.java

@@ -5,6 +5,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
 import com.kxmall.common.annotation.ExcelDictFormat;
 import com.kxmall.common.convert.ExcelDictConvert;
 import com.kxmall.group.domain.vo.KxGroupShopVo;
+import com.kxmall.order.domain.vo.KxOrderScreenshotVo;
 import com.kxmall.rider.domain.vo.KxRiderOrderVo;
 import com.kxmall.user.domain.vo.KxUserVo;
 import lombok.Data;
@@ -405,4 +406,9 @@ public class KxStoreOrderVo {
      */
     private BigDecimal latitude;
 
+    /**
+     * 订单照片列表
+     */
+    private List<KxOrderScreenshotVo> photos;
+
 }

+ 3 - 0
kxmall-system/src/main/java/com/kxmall/rider/domain/vo/KxRiderOrderVo.java

@@ -198,4 +198,7 @@ public class KxRiderOrderVo {
      */
     private List<KxRiderItemVo> riderItemVoList;
 
+    private List<String> imageUrls;
+
+    private List<String> userImageUrls;
 }

+ 2 - 0
kxmall-system/src/main/java/com/kxmall/rider/domain/vo/RiderLoginDTO.java

@@ -11,6 +11,8 @@ import lombok.Data;
 @Data
 public class RiderLoginDTO {
 
+    private Long id;
+
     /**
      * 配送员名称
      */

+ 1 - 1
需求列表.md

@@ -14,7 +14,7 @@
 # 订单互动
 - [ ] 订单内置聊天(*确认需求)
 - [ ] 拨打师傅电话
-- [ ] 评价添加师傅
+- [x] 评价添加师傅
 - [ ] 订单售后-重新服务(*确认需求) xx
 
 # 接单/派单-admin