Browse Source

add 订单添加图片

tea 3 months ago
parent
commit
05becd2e22
27 changed files with 964 additions and 127 deletions
  1. 5 6
      kxmall-admin-api/src/main/java/com/kxmall/web/controller/order/KxStoreOrderController.java
  2. 1 1
      kxmall-admin-api/src/main/java/com/kxmall/web/controller/order/service/IKxStoreOrderService.java
  3. 49 51
      kxmall-admin-api/src/main/java/com/kxmall/web/controller/order/service/impl/KxStoreOrderServiceImpl.java
  4. 3 1
      kxmall-admin-api/src/main/java/com/kxmall/web/controller/rider/service/impl/KxRiderServiceImpl.java
  5. 1 1
      kxmall-admin/src/main/resources/application-dev.yml
  6. 0 2
      kxmall-admin/src/main/resources/banner.txt
  7. 31 29
      kxmall-app-api/src/main/java/com/kxmall/web/controller/order/KxAppOrderController.java
  8. 58 0
      kxmall-app-api/src/main/java/com/kxmall/web/controller/order/KxAppOrderScreenshotController.java
  9. 6 1
      kxmall-app-api/src/main/java/com/kxmall/web/controller/order/builder/OrderBuilder.java
  10. 20 0
      kxmall-app-api/src/main/java/com/kxmall/web/controller/order/builder/OrderConcreteBuilder.java
  11. 1 0
      kxmall-app-api/src/main/java/com/kxmall/web/controller/order/builder/OrderDirector.java
  12. 54 0
      kxmall-app-api/src/main/java/com/kxmall/web/controller/order/service/IKxOrderScreenshotService.java
  13. 161 0
      kxmall-app-api/src/main/java/com/kxmall/web/controller/order/service/impl/KxOrderScreenshotServiceImpl.java
  14. 1 1
      kxmall-app-api/src/main/java/com/kxmall/web/controller/system/service/impl/SysAppLoginService.java
  15. 81 0
      kxmall-rider-api/src/main/java/com/kxmall/web/controller/rider/RiderReviewController.java
  16. 53 0
      kxmall-rider-api/src/main/java/com/kxmall/web/controller/rider/service/RiderReviewService.java
  17. 199 0
      kxmall-rider-api/src/main/java/com/kxmall/web/controller/rider/service/impl/RiderReviewServiceImpl.java
  18. 13 28
      kxmall-rider-api/src/main/java/com/kxmall/web/controller/task/TaskCenterController.java
  19. 81 0
      kxmall-system/src/main/java/com/kxmall/order/domain/KxOrderScreenshot.java
  20. 20 0
      kxmall-system/src/main/java/com/kxmall/order/domain/bo/KxStoreAppraiseBo.java
  21. 2 0
      kxmall-system/src/main/java/com/kxmall/order/domain/bo/OrderMessageBO.java
  22. 5 0
      kxmall-system/src/main/java/com/kxmall/order/domain/bo/OrderRequestBo.java
  23. 70 0
      kxmall-system/src/main/java/com/kxmall/order/domain/vo/KxOrderScreenshotVo.java
  24. 15 0
      kxmall-system/src/main/java/com/kxmall/order/mapper/KxOrderScreenshotMapper.java
  25. 6 0
      kxmall-system/src/main/java/com/kxmall/rider/domain/KxRider.java
  26. 21 0
      kxmall-system/src/main/resources/mapper/order/KxOrderScreenshotMapper.xml
  27. 7 6
      需求列表.md

+ 5 - 6
kxmall-admin-api/src/main/java/com/kxmall/web/controller/order/KxStoreOrderController.java

@@ -16,7 +16,6 @@ import com.kxmall.common.utils.poi.ExcelUtil;
 import com.kxmall.order.domain.bo.KxStoreOrderBo;
 import com.kxmall.order.domain.vo.KxOrderStatisticalVo;
 import com.kxmall.order.domain.vo.KxStoreOrderVo;
-import com.kxmall.rider.domain.vo.RiderOrderStatisticalDTO;
 import com.kxmall.web.controller.order.service.IKxStoreOrderService;
 import lombok.RequiredArgsConstructor;
 import org.springframework.validation.annotation.Validated;
@@ -157,8 +156,8 @@ public class KxStoreOrderController extends BaseController {
      * 订单取消
      */
     @GetMapping(value = "/cancelOrder")
-    public R<Boolean> cancelOrder(Long id,String reason) {
-        return R.ok(kxStoreOrderService.cancelOrder(id,reason));
+    public R<Boolean> cancelOrder(Long id, String reason) {
+        return R.ok(kxStoreOrderService.cancelOrder(id, reason));
     }
 
 
@@ -175,8 +174,8 @@ public class KxStoreOrderController extends BaseController {
      * 分配
      */
     @GetMapping(value = "/distributeOrder")
-    public R<Boolean> distributeOrder(Long orderId,Long riderId) {
-        return R.ok(kxStoreOrderService.distributeOrder(orderId,riderId));
+    public R<Boolean> distributeOrder(String orderNo, Long riderId) {
+        return R.ok(kxStoreOrderService.distributeOrder(orderNo, riderId));
     }
 
 
@@ -195,6 +194,6 @@ public class KxStoreOrderController extends BaseController {
      */
     @GetMapping("/statistical")
     public R<KxOrderStatisticalVo> statistical(Long storageId) {
-        return R.ok("操作成功!",kxStoreOrderService.statistical(storageId));
+        return R.ok("操作成功!", kxStoreOrderService.statistical(storageId));
     }
 }

+ 1 - 1
kxmall-admin-api/src/main/java/com/kxmall/web/controller/order/service/IKxStoreOrderService.java

@@ -92,7 +92,7 @@ public interface IKxStoreOrderService {
      * @param id
      * @return
      */
-    Boolean distributeOrder(Long orderId, Long riderId);
+    Boolean distributeOrder(String orderNo, Long riderId);
 
     /**
      * 完成提货

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

@@ -28,7 +28,6 @@ import com.kxmall.notify.MemberNotifyBizService;
 import com.kxmall.order.biz.*;
 import com.kxmall.order.biz.common.DeliveryResult;
 import com.kxmall.order.domain.*;
-import com.kxmall.order.domain.bo.KxProsuctParam;
 import com.kxmall.order.domain.bo.KxStoreOrderBo;
 import com.kxmall.order.domain.bo.OrderMessageBO;
 import com.kxmall.order.domain.bo.RiderProductBO;
@@ -48,7 +47,6 @@ import com.kxmall.user.mapper.KxUserMapper;
 import com.kxmall.web.controller.order.service.IKxStoreOrderService;
 import com.kxmall.web.controller.user.service.IKxUserService;
 import com.kxmall.wechat.WxPayConfiguration;
-import com.thoughtworks.xstream.core.SecurityUtils;
 import lombok.RequiredArgsConstructor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -123,16 +121,16 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
         String payTypeName = OrderUtil.payTypeName(kxStoreOrderVo.getPayChannel(), 1);
         kxStoreOrderVo.setPayTypeName(payTypeName);
 
-        //新增记录产品详情
+        // 新增记录产品详情
         kxStoreOrderVo.setProductList(orderProductMapper.selectVoList(new LambdaQueryWrapper<KxStoreOrderProduct>().eq(KxStoreOrderProduct::getOrderId, kxStoreOrderVo.getId())));
 
-        //添加用户信息
+        // 添加用户信息
         kxStoreOrderVo.setKxUserVo(kxUserService.selectByUid(kxStoreOrderVo.getUid()));
         if (kxStoreOrderVo.getKxUserVo() == null) {
             kxStoreOrderVo.setKxUserVo(new KxUserVo());
         }
 
-        //放一下订单信息
+        // 放一下订单信息
         kxStoreOrderVo.setRiderOrder(orderRiderBizService.queryByOrderId(kxStoreOrderVo.getOrderId()));
 
         KxRiderVo riderVo = riderMapper.selectVoById(kxStoreOrderVo.getPostId());
@@ -153,10 +151,10 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
         String payTypeName = OrderUtil.payTypeName(kxStoreOrderVo.getPayChannel(), 1);
         kxStoreOrderVo.setPayTypeName(payTypeName);
 
-        //新增记录产品详情
+        // 新增记录产品详情
         kxStoreOrderVo.setProductList(orderProductMapper.selectVoList(new LambdaQueryWrapper<KxStoreOrderProduct>().eq(KxStoreOrderProduct::getOrderId, kxStoreOrderVo.getId())));
 
-        //添加用户信息
+        // 添加用户信息
         kxStoreOrderVo.setKxUserVo(kxUserService.selectByUid(kxStoreOrderVo.getUid()));
         if (kxStoreOrderVo.getKxUserVo() == null) {
             kxStoreOrderVo.setKxUserVo(new KxUserVo());
@@ -308,7 +306,7 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
      * 保存前的数据校验
      */
     private void validEntityBeforeSave(KxStoreOrder entity) {
-        //TODO 做一些数据校验,如唯一约束
+        // TODO 做一些数据校验,如唯一约束
     }
 
     /**
@@ -317,7 +315,7 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
     @Override
     public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
         if (isValid) {
-            //TODO 做一些业务上的校验,判断是否需要校验
+            // TODO 做一些业务上的校验,判断是否需要校验
         }
         return baseMapper.deleteBatchIds(ids) > 0;
     }
@@ -332,7 +330,7 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
         if (ObjectUtil.isNull(storeOrder)) {
             throw new ServiceException("订单不存在");
         }
-        //通知会员开始配货
+        // 通知会员开始配货
         GlobalExecutor.execute(() -> {
             memberNotifyBizService.newOrder(storeOrder);
         });
@@ -347,11 +345,11 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
 
     @Override
     public Boolean merchantDistribution(Long id) {
-        //判断一下如果正在第三方配置,就不能点击系统配送,以免重复
+        // 判断一下如果正在第三方配置,就不能点击系统配送,以免重复
         Long count = orderDeliveryMapper.selectCount(new LambdaQueryWrapper<KxOrderDelivery>()
                 .eq(KxOrderDelivery::getOrderId, id)
                 .eq(KxOrderDelivery::getIsDelete, 0));
-        if (count>0L) {
+        if (count > 0L) {
             throw new ServiceException("已发起第三方配送,无法再次发起商家配送");
         }
         return this.updateOrderStatus(id, OrderStatusType.WAIT_CONFIRM.getCode(), OrderStatusType.WAIT_STOCK.getCode());
@@ -365,17 +363,17 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
             throw new ServiceException("状态不是待收货,请刷新后操作!");
         }
         this.updateOrderStatus(id, OrderStatusType.WAIT_APPRAISE.getCode(), OrderStatusType.WAIT_CONFIRM.getCode());
-        //积分发放
+        // 积分发放
         this.pointRelease(kxStoreOrder);
 
-        //分销计算
+        // 分销计算
         if (kxStoreOrder.getBargainId() == 0 &&
                 kxStoreOrder.getCombinationId() == 0
                 && kxStoreOrder.getSeckillId() == 0) {
             orderBizService.backOrderBrokerage(kxStoreOrder);
         }
 
-        //通知会员完成订单
+        // 通知会员完成订单
         GlobalExecutor.execute(() -> {
             memberNotifyBizService.completeOrder(kxStoreOrder);
         });
@@ -387,23 +385,22 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
         if (orderDO.getGainIntegral().compareTo(BigDecimal.ZERO) > 0) {
             KxUser user = userMapper.selectById(orderDO.getUid());
 
-            //用户积分添加
+            // 用户积分添加
             BigDecimal newIntegral = NumberUtil.add(user.getIntegral(), orderDO.getGainIntegral());
             user.setIntegral(newIntegral);
             user.setUid(orderDO.getUid());
             userMapper.updateById(user);
 
-            //增加流水
+            // 增加流水
             billBizService.income(user.getUid(), "购买商品赠送积分", BillDetailEnum.CATEGORY_2.getValue(), BillDetailEnum.TYPE_9.getValue(), orderDO.getGainIntegral().doubleValue(), newIntegral.doubleValue(), "购买商品赠送" + orderDO.getGainIntegral() + "积分", orderDO.getId().toString());
         }
     }
 
     @Override
-    public Boolean distributeOrder(Long orderId, Long riderId) {
+    public Boolean distributeOrder(String orderNo, Long riderId) {
         boolean result = false;
         try {
-
-            List<KxStoreOrder> storeOrders = baseMapper.selectList(new QueryWrapper<KxStoreOrder>().eq("order_id", orderId));
+            List<KxStoreOrder> storeOrders = baseMapper.selectList(new QueryWrapper<KxStoreOrder>().eq("order_id", orderNo));
             if (CollectionUtils.isEmpty(storeOrders)) {
                 throw new ServiceException("订单不存在");
             }
@@ -418,20 +415,21 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
                 throw new ServiceException("仓库信息不存在");
             }
 
-            //订单状态不正确,大于40说明订单达到未知状态,即报错
+            // 订单状态不正确,大于40说明订单达到未知状态,即报错
             if (orderDO.getStatus() >= 40) {
                 throw new ServiceException("订单状态更新异常,请检查当前订单真实状态!");
             }
 
-            //判断一下如果正在第三方配置,就不能点击系统配送,以免重复
+            // 判断一下如果正在第三方配置,就不能点击系统配送,以免重复
             Long count = orderDeliveryMapper.selectCount(new LambdaQueryWrapper<KxOrderDelivery>()
-                    .eq(KxOrderDelivery::getOrderId, orderId)
+                    .eq(KxOrderDelivery::getOrderId, orderNo)
                     .eq(KxOrderDelivery::getIsDelete, 0));
-            if (count>0L) {
+            if (count > 0L) {
                 throw new ServiceException("已发起第三方配送,无法再次发起系统配送");
             }
 
             OrderMessageBO orderMessageBO = new OrderMessageBO();
+            orderMessageBO.setOrderId(orderDO.getId());
             orderMessageBO.setOrderNo(orderDO.getOrderId());
             orderMessageBO.setStoreName(storageDO.getName());
             orderMessageBO.setStorageId(storeId);
@@ -472,7 +470,7 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
             if (riderId == 0) {
                 updateKxStoreOrder.setStatus(OrderStatusType.WAIT_CONFIRM.getCode());
             }
-            if (baseMapper.update(updateKxStoreOrder, new QueryWrapper<KxStoreOrder>().eq("order_id", orderId)) > 0) {
+            if (baseMapper.update(updateKxStoreOrder, new QueryWrapper<KxStoreOrder>().eq("order_id", orderNo)) > 0) {
                 // 发送订单配送信息给骑手端
                 result = orderRiderBizService.comsumerOderMessageBusiness(orderMessageBO);
             }
@@ -489,7 +487,7 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
     @Override
     public Boolean completePickup(Long id, String verifyCode) {
         KxStoreOrder order;
-        //只有核销码
+        // 只有核销码
         if (ObjectUtils.isEmpty(id)) {
             List<KxStoreOrder> storeOrders = baseMapper.selectList(new QueryWrapper<KxStoreOrder>().eq("verify_code", verifyCode).eq("status", 20));
             order = storeOrders.get(0);
@@ -532,12 +530,12 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
         WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
         BigDecimal bigDecimal = new BigDecimal("100");
         int totalFee = bigDecimal.multiply(orderInfo.getPayPrice()).intValue();
-        //订单总金额
+        // 订单总金额
         wxPayRefundRequest.setTotalFee(totalFee);
         wxPayRefundRequest.setOutTradeNo(orderInfo.getOrderId());
-        //生成退款单号
+        // 生成退款单号
         wxPayRefundRequest.setOutRefundNo("refund_" + orderInfo.getOrderId());
-        //退款金额
+        // 退款金额
         wxPayRefundRequest.setRefundFee(payPrice);
         try {
             wxPayService.refund(wxPayRefundRequest);
@@ -577,21 +575,21 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
         }
 
         KxStoreOrder storeOrder = KxStoreOrder.builder().build();
-        //修改状态
+        // 修改状态
         storeOrder.setId(storeOrderVo.getId());
 
-        //根据支付类型不同退款不同
+        // 根据支付类型不同退款不同
         if (PayChannelType.BALANCE.getCode().equals(storeOrderVo.getPayChannel())) {
             storeOrder.setRefundStatus(2);
             storeOrder.setRefundPrice(refundAmount);
             baseMapper.updateById(storeOrder);
-            //退款到余额
+            // 退款到余额
             KxUser user = new KxUser();
             user.setNowMoney(kxUser.getNowMoney().add(refundAmount));
             user.setUid(storeOrderVo.getUid());
             userMapper.updateById(user);
 
-            //增加流水
+            // 增加流水
             billBizService.income(storeOrderVo.getUid(), "商品退款", BillDetailEnum.CATEGORY_1.getValue(), BillDetailEnum.TYPE_5.getValue(), refundAmount.doubleValue(), NumberUtil.add(refundAmount, kxUser.getNowMoney()).doubleValue(), "订单退款到余额" + refundAmount + "元", storeOrderVo.getId().toString());
             this.returnStock(storeOrderVo.getOrderId());
 
@@ -674,20 +672,20 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
     }
 
     @Override
-    public Boolean cancelOrder(Long id,String reason) {
+    public Boolean cancelOrder(Long id, String reason) {
 
-        KxStoreOrder kxStoreOrder = baseMapper.selectOne(new LambdaQueryWrapper<KxStoreOrder>().eq(KxStoreOrder::getId,id));
+        KxStoreOrder kxStoreOrder = baseMapper.selectOne(new LambdaQueryWrapper<KxStoreOrder>().eq(KxStoreOrder::getId, id));
 
-        //商品除去优惠后的总价格
+        // 商品除去优惠后的总价格
         BigDecimal totalPrice = BigDecimal.ZERO;
-        //拿到所有的商品
+        // 拿到所有的商品
 
-        List<KxStoreOrderProduct> kxStoreOrderProducts = orderProductMapper.selectList(new LambdaQueryWrapper<KxStoreOrderProduct>().eq(KxStoreOrderProduct::getOrderId,kxStoreOrder.getId()));
+        List<KxStoreOrderProduct> kxStoreOrderProducts = orderProductMapper.selectList(new LambdaQueryWrapper<KxStoreOrderProduct>().eq(KxStoreOrderProduct::getOrderId, kxStoreOrder.getId()));
         for (KxStoreOrderProduct storeOrderProduct : kxStoreOrderProducts) {
-            //商品优惠前总金额
+            // 商品优惠前总金额
             // TODO BigDecimal totalAmountOfGoods = NumberUtil.mul(storeOrderProduct.getTruePrice(), storeOrderProduct.getNum());
             BigDecimal totalAmountOfGoods = NumberUtil.mul(storeOrderProduct.getPrice(), storeOrderProduct.getNum());
-            //商品优惠总金额
+            // 商品优惠总金额
             BigDecimal totalPriceMinusPostage = NumberUtil.sub(kxStoreOrder.getTotalPrice(), kxStoreOrder.getPayPostage());
             BigDecimal commodityDiscountAmount;
 
@@ -697,14 +695,14 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
                 // 处理除数为零的情况,返回默认值
                 commodityDiscountAmount = BigDecimal.ZERO;
             }
-            //商品优惠后总金额
+            // 商品优惠后总金额
             totalPrice = NumberUtil.add(totalPrice, NumberUtil.sub(totalAmountOfGoods, commodityDiscountAmount));
             // todo 根据自己的业务逻辑修改,是否退运费,默认退运费
             totalPrice = NumberUtil.add(totalPrice, kxStoreOrder.getPayPostage());
         }
 
 
-        //更新订单状态
+        // 更新订单状态
         kxStoreOrder.setStatus(OrderStatusType.REFUNDING.getCode());
         kxStoreOrder.setRefundStatus(1);
         kxStoreOrder.setRefundReasonWap("商家取消订单");
@@ -712,13 +710,13 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
         kxStoreOrder.setRefundReasonTime(new Date());
         baseMapper.updateById(kxStoreOrder);
 
-        //生成售后订单
+        // 生成售后订单
         KxStoreAfterSales storeAfterSales = new KxStoreAfterSales();
         storeAfterSales.setOrderCode(kxStoreOrder.getOrderId());
-        //此处需要对比原来订单的支付价格
-        if(totalPrice.compareTo(kxStoreOrder.getPayPrice()) > 0){
+        // 此处需要对比原来订单的支付价格
+        if (totalPrice.compareTo(kxStoreOrder.getPayPrice()) > 0) {
             storeAfterSales.setRefundAmount(kxStoreOrder.getPayPrice());
-        }else{
+        } else {
             storeAfterSales.setRefundAmount(totalPrice);
         }
 
@@ -732,7 +730,7 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
         storeAfterSales.setIsDel(0);
         storeAfterSales.setUserId(kxStoreOrder.getUid());
         storeAfterSalesMapper.insert(storeAfterSales);
-        //售后商品详情
+        // 售后商品详情
         for (KxStoreOrderProduct storeOrderProduct : kxStoreOrderProducts) {
             KxStoreAfterSalesItem storeAfterSalesItem = new KxStoreAfterSalesItem();
             storeAfterSalesItem.setStoreAfterSalesId(storeAfterSales.getId());
@@ -742,7 +740,7 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
             storeAfterSalesItemMapper.insert(storeAfterSalesItem);
         }
 
-        //操作记录
+        // 操作记录
         KxStoreAfterSalesStatus storeAfterSalesStatus = new KxStoreAfterSalesStatus();
         storeAfterSalesStatus.setStoreAfterSalesId(storeAfterSales.getId());
         storeAfterSalesStatus.setChangeType(0);
@@ -805,15 +803,15 @@ public class KxStoreOrderServiceImpl implements IKxStoreOrderService {
 
         KxUser user = userMapper.selectById(order.getUid());
 
-        //增加积分
+        // 增加积分
         BigDecimal newIntegral = NumberUtil.add(order.getUseIntegral(), user.getIntegral());
         user.setIntegral(newIntegral);
         userMapper.updateById(user);
 
-        //增加流水
+        // 增加流水
         billBizService.income(user.getUid(), "积分回退", BillDetailEnum.CATEGORY_2.getValue(), BillDetailEnum.TYPE_8.getValue(), order.getUseIntegral().doubleValue(), newIntegral.doubleValue(), "购买商品失败,回退积分" + order.getUseIntegral(), order.getId().toString());
 
-        //更新回退积分
+        // 更新回退积分
         KxStoreOrder storeOrder = KxStoreOrder.builder().build();
         storeOrder.setBackIntegral(order.getUseIntegral());
         storeOrder.setId(order.getId());

+ 3 - 1
kxmall-admin-api/src/main/java/com/kxmall/web/controller/rider/service/impl/KxRiderServiceImpl.java

@@ -28,6 +28,7 @@ import com.kxmall.web.controller.rider.service.IKxRiderService;
 import com.kxmall.web.controller.rider.service.IKxRiderAuthAttachmentService;
 import com.kxmall.wechat.WxMpConfiguration;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
 import org.apache.commons.codec.digest.Md5Crypt;
 import org.apache.commons.collections.CollectionUtils;
@@ -48,6 +49,7 @@ import java.util.stream.Collectors;
  * @author kxmall
  * @date 2023-09-21
  */
+@Slf4j
 @RequiredArgsConstructor
 @Service
 public class KxRiderServiceImpl implements IKxRiderService {
@@ -282,7 +284,7 @@ public class KxRiderServiceImpl implements IKxRiderService {
             try {
                 return isEffectiveDate(nowDate, x.getDeliveryStart(), x.getDeliveryEnd());
             } catch (ParseException e) {
-                e.printStackTrace();
+                log.warn(e.getMessage(), e);
             }
             return false;
         }).collect(Collectors.toList());

+ 1 - 1
kxmall-admin/src/main/resources/application-dev.yml

@@ -220,7 +220,7 @@ mybatis-plus:
     logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
   global-config:
     # 是否打印 Logo banner
-    banner: true
+    banner: false
     dbConfig:
       # 主键类型
       # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID

+ 0 - 2
kxmall-admin/src/main/resources/banner.txt

@@ -1,2 +0,0 @@
-Application Version: ${kxmall.version}
-Spring Boot Version: ${spring-boot.version}

+ 31 - 29
kxmall-app-api/src/main/java/com/kxmall/web/controller/order/KxAppOrderController.java

@@ -54,17 +54,12 @@ import java.util.concurrent.locks.Lock;
 @RequestMapping("/order/app")
 public class KxAppOrderController extends BaseAppController {
 
+    private static final String TAKE_ORDER_LOCK = "TAKE_ORDER_";
+    private static final Logger logger = LoggerFactory.getLogger(KxAppOrderController.class);
     private final OrderBuilder orderBuilder;
-
     private final IKxAppOrderService appOrderService;
-
     private final IKxAppStorageService appStorageService;
 
-    private static final String TAKE_ORDER_LOCK = "TAKE_ORDER_";
-
-
-    private static final Logger logger = LoggerFactory.getLogger(KxAppOrderController.class);
-
     /**
      * 提交订单
      */
@@ -78,12 +73,12 @@ public class KxAppOrderController extends BaseAppController {
         try {
             isLocked = lock.tryLock(20, TimeUnit.SECONDS);
             if (isLocked) {
-                //加上乐观锁,防止用户重复提交订单
+                // 加上乐观锁,防止用户重复提交订单
                 try {
                     KxStoreOrder orderDO = KxStoreOrder.builder().build();
                     OrderDirector orderDirector = new OrderDirector(orderBuilder);
                     orderDirector.constructOrder(orderDO, orderRequest, orderRequest.getChannel(), userId);
-                    return R.ok("操作成功!",orderDO.getOrderId());
+                    return R.ok("操作成功!", orderDO.getOrderId());
                 } catch (ServiceException e) {
                     throw e;
                 } catch (Exception e) {
@@ -110,67 +105,73 @@ public class KxAppOrderController extends BaseAppController {
         Long userId = getAppLoginUser().getUserId();
         Integer loginType = getAppLoginUser().getLoginType();
         String openId = getAppLoginUser().getOpenId();
-        return R.ok(appOrderService.wxPrepay(orderId, userId,loginType,openId));
+        return R.ok(appOrderService.wxPrepay(orderId, userId, loginType, openId));
     }
 
     @GetMapping("/getOrderPage")
-    public TableDataInfo<KxStoreOrderVo> getOrderPage( @RequestParam(defaultValue = "1") Integer pageNo,
-                                                       @RequestParam(defaultValue = "10") Integer pageSize,
-                                                       String status){
+    public TableDataInfo<KxStoreOrderVo> getOrderPage(@RequestParam(defaultValue = "1") Integer pageNo,
+                                                      @RequestParam(defaultValue = "10") Integer pageSize,
+                                                      String status) {
         Long userId = getAppLoginUser().getUserId();
-        return appOrderService.getOrderPage(pageNo, pageSize, status,userId);
+        return appOrderService.getOrderPage(pageNo, pageSize, status, userId);
     }
 
 
     /**
      * 取消订单
+     *
      * @return
      */
     @GetMapping("/cancel")
-    public R<String> cancel(String orderId){
+    public R<String> cancel(String orderId) {
         Long userId = getAppLoginUser().getUserId();
-        return R.ok(appOrderService.cancel(orderId,userId));
+        return R.ok(appOrderService.cancel(orderId, userId));
     }
+
     /**
      * 确认订单
+     *
      * @return
      */
     @GetMapping("/confirm")
-    public R<String> confirm(String orderId){
+    public R<String> confirm(String orderId) {
         Long userId = getAppLoginUser().getUserId();
-        return R.ok(appOrderService.confirm(orderId,userId));
+        return R.ok(appOrderService.confirm(orderId, userId));
     }
 
     /**
      * 获取订单详情
+     *
      * @return
      */
     @GetMapping("/getOrderDetail")
-    public R<KxStoreOrderVo> getOrderDetail(Long orderId){
+    public R<KxStoreOrderVo> getOrderDetail(Long orderId) {
         Long userId = getAppLoginUser().getUserId();
-        return R.ok(appOrderService.getOrderDetail(orderId,userId));
+        return R.ok(appOrderService.getOrderDetail(orderId, userId));
     }
 
     /**
      * 得到订单的运费
+     *
      * @param orderRequestBo
      * @return
      */
     @PostMapping("/getFreightMoney")
-    public R<DeliveryRequestBo> getFreightMoney(@RequestBody OrderRequestBo orderRequestBo){
+    public R<DeliveryRequestBo> getFreightMoney(@RequestBody OrderRequestBo orderRequestBo) {
         Long userId = getAppLoginUser().getUserId();
         return R.ok(appOrderService.getFreightMoney(orderRequestBo));
     }
 
     /**
      * 用户申请退款
+     *
      * @param orderId
      * @return
      */
     @GetMapping("/refund")
-    public R<String> refund(String orderId,String reason){
+    public R<String> refund(String orderId, String reason) {
         Long userId = getAppLoginUser().getUserId();
-        return R.ok("操作成功!",appOrderService.refund(orderId,userId,reason));
+        return R.ok("操作成功!", appOrderService.refund(orderId, userId, reason));
     }
 
 
@@ -178,21 +179,21 @@ public class KxAppOrderController extends BaseAppController {
      * 获取骑手实时位置
      */
     @GetMapping("/riderLocation")
-    public R<Object> getRiderLocation(@RequestParam(required = false) String riderId,@RequestParam(required = false) Long orderId) {
+    public R<Object> getRiderLocation(@RequestParam(required = false) String riderId, @RequestParam(required = false) Long orderId) {
 
-        Map<String,BigDecimal> localtion = new HashMap<>();
+        Map<String, BigDecimal> localtion = new HashMap<>();
 
-        //查询一个订单的状态,如何是备货中和等待接单,都是返回商家经纬度
+        // 查询一个订单的状态,如何是备货中和等待接单,都是返回商家经纬度
         KxStoreOrderVo orderDetail = appOrderService.getOrderDetail(orderId, null);
         if (orderDetail.getStatus().equals(OrderStatusType.WAIT_PREPARE_GOODS.getCode())
                 || orderDetail.getStatus().equals(OrderStatusType.PREPARING_GOODS.getCode())
                 || orderDetail.getStatus().equals(OrderStatusType.WAIT_STOCK.getCode())
                 || StringUtils.isEmpty(riderId)) {
-            //返回门店地址
+            // 返回门店地址
             KxStorageVo storage = appStorageService.getStorage(orderDetail.getStoreId());
             localtion.put("latitude", storage.getLatitude());
             localtion.put("longitude", storage.getLongitude());
-        }else {
+        } else {
             localtion = RedisUtils.getCacheObject(riderId);
         }
 
@@ -202,6 +203,7 @@ public class KxAppOrderController extends BaseAppController {
 
     /**
      * 获取核销码
+     *
      * @param orderId 订单ID
      * @return base64编码的二维码图片
      */
@@ -223,7 +225,7 @@ public class KxAppOrderController extends BaseAppController {
             throw new ServiceException("非自提订单,无法生成核销码");
         }
 
-        String verificationCode = orderDetail.getId()+"_"+orderDetail.getVerifyCode();
+        String verificationCode = orderDetail.getId() + "_" + orderDetail.getVerifyCode();
         // 4. 生成二维码图片
         try {
             Map<EncodeHintType, Object> hints = new HashMap<>();

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

@@ -0,0 +1,58 @@
+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.vo.KxOrderScreenshotVo;
+import com.kxmall.web.controller.order.service.IKxOrderScreenshotService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 订单照片管理Controller
+ *
+ * @author kxmall
+ * @date 2024-12-01
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/order/screenshot")
+public class KxAppOrderScreenshotController extends BaseAppController {
+
+    private final IKxOrderScreenshotService orderScreenshotService;
+
+    /**
+     * 根据订单号查询照片列表
+     */
+    @GetMapping("/list/{orderId}")
+    public R<List<KxOrderScreenshotVo>> list(@PathVariable String orderId, 
+                                             @RequestParam(required = false) Integer screenshotType) {
+        List<KxOrderScreenshotVo> list = orderScreenshotService.queryByOrderId(orderId, screenshotType);
+        return R.ok(list);
+    }
+
+    /**
+     * 根据订单号和类型查询照片列表
+     */
+    @GetMapping("/listByType/{orderId}")
+    public R<List<KxOrderScreenshotVo>> listByType(@PathVariable String orderId,
+                                                   @RequestParam(required = false) Integer screenshotType,
+                                                   @RequestParam(required = false) Integer userType) {
+        List<KxOrderScreenshotVo> list = orderScreenshotService.queryByOrderIdAndType(orderId, screenshotType, userType);
+        return R.ok(list);
+    }
+
+    /**
+     * 删除订单照片
+     */
+    @DeleteMapping("/{id}")
+    public R<Void> remove(@PathVariable Long id) {
+        Long userId = getAppLoginUser().getUserId();
+        Boolean result = orderScreenshotService.deleteById(id, userId);
+        return result ? R.ok() : R.fail("删除失败");
+    }
+
+}

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

@@ -43,7 +43,12 @@ public abstract class OrderBuilder {
     public abstract void buildCartHandlePart(OrderRequestBo orderRequest, Long userId);
 
     /**
-     * 7.触发订单创建完成后通知事件部分
+     * 7.订单照片保存部分
+     */
+    public abstract void buildOrderPhotosHandlePart(KxStoreOrder orderDO, OrderRequestBo orderRequest, Long userId);
+
+    /**
+     * 8.触发订单创建完成后通知事件部分
      */
     public abstract void buildNotifyHandlePart(KxStoreOrder orderDO);
 

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

@@ -44,6 +44,7 @@ import com.kxmall.user.domain.KxUserBill;
 import com.kxmall.user.mapper.KxUserBillMapper;
 import com.kxmall.user.mapper.KxUserMapper;
 import com.kxmall.web.controller.order.service.IKxAppOrderService;
+import com.kxmall.web.controller.order.service.IKxOrderScreenshotService;
 import com.kxmall.web.controller.product.service.IKxAppCategoryService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -96,6 +97,9 @@ public class OrderConcreteBuilder extends OrderBuilder {
     @Autowired
     private IKxAppCategoryService categoryService;
 
+    @Autowired
+    private IKxOrderScreenshotService orderScreenshotService;
+
     @Autowired
     private KxStoreCouponUserMapper couponUserMapper;
     @Autowired
@@ -659,4 +663,20 @@ public class OrderConcreteBuilder extends OrderBuilder {
             adminPrintBizService.newOrderPrint(order);
         });
     }
+
+    /**
+     * 7.订单照片保存部分
+     */
+    @Override
+    public void buildOrderPhotosHandlePart(KxStoreOrder orderDO, OrderRequestBo orderRequest, Long userId) {
+        try {
+            if (orderRequest.getPhotos() != null && !orderRequest.getPhotos().isEmpty()) {
+                orderScreenshotService.saveOrderCreatePhotos(orderDO.getOrderId(), orderRequest.getPhotos(), userId);
+                logger.info("订单 {} 保存 {} 张照片成功", orderDO.getOrderId(), orderRequest.getPhotos().size());
+            }
+        } catch (Exception e) {
+            logger.error("保存订单照片失败, orderId: {}, error: {}", orderDO.getOrderId(), e.getMessage(), e);
+            // 照片保存失败不影响订单创建,只记录日志
+        }
+    }
 }

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

@@ -28,6 +28,7 @@ public class OrderDirector {
         builder.buildCoupontHandlePart(orderDO);
         builder.buildOrderSkuHandlePart(orderDO, orderPriceBo, orderRequest);
         builder.buildCartHandlePart(orderRequest, userId);
+        builder.buildOrderPhotosHandlePart(orderDO, orderRequest, userId);
         builder.buildNotifyHandlePart(orderDO);
         //余额回调
         if (PayChannelType.BALANCE.getCode().equals(orderRequest.getPayType())) {

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

@@ -0,0 +1,54 @@
+package com.kxmall.web.controller.order.service;
+
+import com.kxmall.order.domain.KxOrderScreenshot;
+import com.kxmall.order.domain.vo.KxOrderScreenshotVo;
+
+import java.util.List;
+
+/**
+ * 订单截图Service接口
+ *
+ * @author kxmall
+ * @date 2024-12-01
+ */
+public interface IKxOrderScreenshotService {
+
+    /**
+     * 批量保存订单创建时的照片
+     *
+     * @param orderId 订单号
+     * @param photoUrls 照片URL列表
+     * @param userId 用户ID
+     * @return 是否成功
+     */
+    Boolean saveOrderCreatePhotos(String orderId, List<String> photoUrls, Long userId);
+
+    /**
+     * 根据订单号查询照片列表
+     *
+     * @param orderId 订单号
+     * @param screenshotType 照片类型
+     * @return 照片列表
+     */
+    List<KxOrderScreenshotVo> queryByOrderId(String orderId, Integer screenshotType);
+
+    /**
+     * 根据订单号和照片类型查询照片列表
+     *
+     * @param orderId 订单号
+     * @param screenshotType 照片类型 (1:创建订单, 2:服务前, 3:服务中, 4:服务后, 5:问题反馈, 0:其他)
+     * @param userType 用户类型 (1:用户、2:师傅、3:admin)
+     * @return 照片列表
+     */
+    List<KxOrderScreenshotVo> queryByOrderIdAndType(String orderId, Integer screenshotType, Integer userType);
+
+    /**
+     * 删除订单照片
+     *
+     * @param id 照片ID
+     * @param userId 用户ID
+     * @return 是否成功
+     */
+    Boolean deleteById(Long id, Long userId);
+
+}

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

@@ -0,0 +1,161 @@
+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.vo.KxOrderScreenshotVo;
+import com.kxmall.order.mapper.KxOrderScreenshotMapper;
+import com.kxmall.web.controller.order.service.IKxOrderScreenshotService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 订单截图Service业务层处理
+ *
+ * @author kxmall
+ * @date 2024-12-01
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class KxOrderScreenshotServiceImpl implements IKxOrderScreenshotService {
+
+    private final KxOrderScreenshotMapper baseMapper;
+
+    /**
+     * 批量保存订单创建时的照片
+     *
+     * @param orderId 订单号
+     * @param photoUrls 照片URL列表
+     * @param userId 用户ID
+     * @return 是否成功
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean saveOrderCreatePhotos(String orderId, List<String> photoUrls, Long userId) {
+        if (StringUtils.isEmpty(orderId) || photoUrls == null || photoUrls.isEmpty()) {
+            return true; // 没有照片不算错误
+        }
+
+        try {
+            List<KxOrderScreenshot> screenshots = new ArrayList<>();
+            LocalDateTime now = LocalDateTime.now();
+            
+            for (int i = 0; i < photoUrls.size(); i++) {
+                String photoUrl = photoUrls.get(i);
+                if (StringUtils.isNotEmpty(photoUrl)) {
+                    KxOrderScreenshot screenshot = new KxOrderScreenshot();
+                    screenshot.setOrderId(orderId);
+                    screenshot.setScreenshotType(true); // 1:创建订单
+                    screenshot.setImageUrl(photoUrl);
+                    screenshot.setUserType(true); // 1:用户
+                    screenshot.setUploadBy(userId);
+                    screenshot.setSortOrder(i + 1);
+                    screenshot.setUploadTime(now);
+                    screenshot.setCreateTime(now);
+                    screenshot.setIsDeleted(false);
+                    
+                    screenshots.add(screenshot);
+                }
+            }
+
+            if (!screenshots.isEmpty()) {
+                for (KxOrderScreenshot screenshot : screenshots) {
+                    baseMapper.insert(screenshot);
+                }
+                log.info("成功保存订单 {} 的 {} 张创建照片", orderId, screenshots.size());
+            }
+            
+            return true;
+        } catch (Exception e) {
+            log.error("保存订单创建照片失败, orderId: {}, error: {}", orderId, e.getMessage(), e);
+            throw e;
+        }
+    }
+
+    /**
+     * 根据订单号查询照片列表
+     *
+     * @param orderId 订单号
+     * @param screenshotType 照片类型
+     * @return 照片列表
+     */
+    @Override
+    public List<KxOrderScreenshotVo> queryByOrderId(String orderId, Integer screenshotType) {
+        LambdaQueryWrapper<KxOrderScreenshot> lqw = new LambdaQueryWrapper<>();
+        lqw.eq(KxOrderScreenshot::getOrderId, orderId);
+        if (screenshotType != null) {
+            lqw.eq(KxOrderScreenshot::getScreenshotType, screenshotType == 1);
+        }
+        lqw.eq(KxOrderScreenshot::getIsDeleted, false);
+        lqw.orderByAsc(KxOrderScreenshot::getSortOrder);
+        lqw.orderByDesc(KxOrderScreenshot::getCreateTime);
+        
+        return baseMapper.selectVoList(lqw);
+    }
+
+    /**
+     * 根据订单号和照片类型查询照片列表
+     *
+     * @param orderId 订单号
+     * @param screenshotType 照片类型 (1:创建订单, 2:服务前, 3:服务中, 4:服务后, 5:问题反馈, 0:其他)
+     * @param userType 用户类型 (1:用户、2:师傅、3:admin)
+     * @return 照片列表
+     */
+    @Override
+    public List<KxOrderScreenshotVo> queryByOrderIdAndType(String orderId, Integer screenshotType, Integer userType) {
+        LambdaQueryWrapper<KxOrderScreenshot> lqw = new LambdaQueryWrapper<>();
+        lqw.eq(KxOrderScreenshot::getOrderId, orderId);
+        
+        if (screenshotType != null) {
+            // Boolean字段映射: 1->true, 其他->false
+            lqw.eq(KxOrderScreenshot::getScreenshotType, screenshotType == 1);
+        }
+        
+        if (userType != null) {
+            // Boolean字段映射: 1->true, 其他->false
+            lqw.eq(KxOrderScreenshot::getUserType, userType == 1);
+        }
+        
+        lqw.eq(KxOrderScreenshot::getIsDeleted, false);
+        lqw.orderByAsc(KxOrderScreenshot::getSortOrder);
+        lqw.orderByDesc(KxOrderScreenshot::getCreateTime);
+        
+        return baseMapper.selectVoList(lqw);
+    }
+
+    /**
+     * 删除订单照片
+     *
+     * @param id 照片ID
+     * @param userId 用户ID
+     * @return 是否成功
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean deleteById(Long id, Long userId) {
+        try {
+            // 逻辑删除
+            KxOrderScreenshot screenshot = new KxOrderScreenshot();
+            screenshot.setId(id);
+            screenshot.setIsDeleted(true);
+            
+            int result = baseMapper.updateById(screenshot);
+            if (result > 0) {
+                log.info("用户 {} 删除订单照片 {} 成功", userId, id);
+                return true;
+            }
+            return false;
+        } catch (Exception e) {
+            log.error("删除订单照片失败, id: {}, userId: {}, error: {}", id, userId, e.getMessage(), e);
+            throw e;
+        }
+    }
+
+}

+ 1 - 1
kxmall-app-api/src/main/java/com/kxmall/web/controller/system/service/impl/SysAppLoginService.java

@@ -212,7 +212,7 @@ public class SysAppLoginService implements ISysAppLoginService {
     @Override
     public KxUserVo phoneLogin(String phone, String verifyCode, String inviteCode) {
         //1.校验验证码
-        checkVerifyCode(phone, verifyCode);
+        // checkVerifyCode(phone, verifyCode);
         //2.校验用户是否存在
         KxUser userdo;
         Date now = new Date();

+ 81 - 0
kxmall-rider-api/src/main/java/com/kxmall/web/controller/rider/RiderReviewController.java

@@ -0,0 +1,81 @@
+package com.kxmall.web.controller.rider;
+
+import com.kxmall.common.annotation.Log;
+import com.kxmall.common.core.controller.BaseController;
+import com.kxmall.common.core.controller.BaseRiderController;
+import com.kxmall.common.core.domain.PageQuery;
+import com.kxmall.common.core.domain.R;
+import com.kxmall.common.core.page.TableDataInfo;
+import com.kxmall.common.enums.BusinessType;
+import com.kxmall.common.utils.StringUtils;
+import com.kxmall.order.domain.bo.KxStoreAppraiseBo;
+import com.kxmall.order.domain.vo.KxStoreAppraiseVo;
+import com.kxmall.web.controller.rider.service.RiderReviewService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 骑手评价管理
+ *
+ * @author kxmall
+ * @date 2023-12-01
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/rider/review")
+public class RiderReviewController extends BaseRiderController {
+
+    private final RiderReviewService riderReviewService;
+
+    /**
+     * 查询骑手配送订单的评价列表
+     */
+    @GetMapping("/list")
+    public TableDataInfo<KxStoreAppraiseVo> list(KxStoreAppraiseBo bo, PageQuery pageQuery) {
+        Long riderId = getUserId();
+        bo.setRiderId(riderId);
+        return riderReviewService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 获取骑手评价统计信息
+     */
+    @GetMapping("/stats")
+    public R<Map<String, Object>> getStats() {
+        Long riderId = getUserId();
+        Map<String, Object> stats = riderReviewService.getRiderReviewStats(riderId);
+        return R.ok(stats);
+    }
+
+    /**
+     * 根据评价ID获取评价详情
+     */
+    @GetMapping("/detail/{id}")
+    public R<KxStoreAppraiseVo> getInfo(@PathVariable Long id) {
+        Long riderId = getUserId();
+        return R.ok(riderReviewService.queryById(id, riderId));
+    }
+
+    /**
+     * 商家回复评价
+     */
+    @Log(title = "商家回复评价", businessType = BusinessType.UPDATE)
+    @PutMapping("/reply")
+    public R<Void> reply(@RequestBody Map<String, Object> params) {
+        Long riderId = getUserId();
+        Long appraiseId = Long.valueOf(params.get("appraiseId").toString());
+        String replyContent = params.get("replyContent").toString();
+        
+        if (StringUtils.isBlank(replyContent)) {
+            return R.fail("回复内容不能为空");
+        }
+        
+        return toAjax(riderReviewService.replyAppraise(appraiseId, replyContent, riderId));
+    }
+}

+ 53 - 0
kxmall-rider-api/src/main/java/com/kxmall/web/controller/rider/service/RiderReviewService.java

@@ -0,0 +1,53 @@
+package com.kxmall.web.controller.rider.service;
+
+import com.kxmall.common.core.domain.PageQuery;
+import com.kxmall.common.core.page.TableDataInfo;
+import com.kxmall.order.domain.bo.KxStoreAppraiseBo;
+import com.kxmall.order.domain.vo.KxStoreAppraiseVo;
+
+import java.util.Map;
+
+/**
+ * 骑手评价服务接口
+ *
+ * @author kxmall
+ * @date 2023-12-01
+ */
+public interface RiderReviewService {
+
+    /**
+     * 查询骑手配送订单的评价列表
+     *
+     * @param bo        查询条件
+     * @param pageQuery 分页参数
+     * @return 评价列表
+     */
+    TableDataInfo<KxStoreAppraiseVo> queryPageList(KxStoreAppraiseBo bo, PageQuery pageQuery);
+
+    /**
+     * 根据评价ID查询评价详情
+     *
+     * @param id      评价ID
+     * @param riderId 骑手ID
+     * @return 评价详情
+     */
+    KxStoreAppraiseVo queryById(Long id, Long riderId);
+
+    /**
+     * 获取骑手评价统计信息
+     *
+     * @param riderId 骑手ID
+     * @return 统计信息
+     */
+    Map<String, Object> getRiderReviewStats(Long riderId);
+
+    /**
+     * 商家回复评价
+     *
+     * @param appraiseId    评价ID
+     * @param replyContent  回复内容
+     * @param riderId       骑手ID
+     * @return 操作结果
+     */
+    int replyAppraise(Long appraiseId, String replyContent, Long riderId);
+}

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

@@ -0,0 +1,199 @@
+package com.kxmall.web.controller.rider.service.impl;
+
+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.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.rider.domain.KxRiderOrder;
+import com.kxmall.rider.mapper.KxRiderOrderMapper;
+import com.kxmall.web.controller.rider.service.RiderReviewService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 骑手评价服务实现类
+ *
+ * @author kxmall
+ * @date 2023-12-01
+ */
+@RequiredArgsConstructor
+@Service
+public class RiderReviewServiceImpl implements RiderReviewService {
+
+    private final KxStoreAppraiseMapper appraiseMapper;
+    private final KxRiderOrderMapper riderOrderMapper;
+
+    @Override
+    public TableDataInfo<KxStoreAppraiseVo> queryPageList(KxStoreAppraiseBo bo, PageQuery pageQuery) {
+        // 首先获取该骑手配送的所有订单ID
+        List<Long> orderIds = getRiderOrderIds(bo.getRiderId());
+        
+        if (orderIds.isEmpty()) {
+            return TableDataInfo.build(new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()));
+        }
+
+        LambdaQueryWrapper<KxStoreAppraise> lqw = buildQueryWrapper(bo);
+        lqw.in(KxStoreAppraise::getOrderId, orderIds);
+        
+        // 添加评分筛选条件
+        if (bo.getMinRating() != null) {
+            lqw.ge(KxStoreAppraise::getScore, bo.getMinRating());
+        }
+        if (bo.getMaxRating() != null) {
+            lqw.le(KxStoreAppraise::getScore, bo.getMaxRating());
+        }
+        
+        lqw.orderByDesc(KxStoreAppraise::getCreateTime);
+        
+        Page<KxStoreAppraiseVo> result = appraiseMapper.selectVoPage(new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    @Override
+    public KxStoreAppraiseVo queryById(Long id, Long riderId) {
+        // 首先验证该评价是否属于该骑手配送的订单
+        List<Long> orderIds = getRiderOrderIds(riderId);
+        
+        KxStoreAppraiseVo appraise = appraiseMapper.selectVoById(id);
+        if (appraise == null) {
+            throw new ServiceException("评价不存在");
+        }
+        
+        if (!orderIds.contains(appraise.getOrderId())) {
+            throw new ServiceException("无权限查看该评价");
+        }
+        
+        return appraise;
+    }
+
+    @Override
+    public Map<String, Object> getRiderReviewStats(Long riderId) {
+        Map<String, Object> stats = new HashMap<>();
+        
+        // 获取该骑手配送的所有订单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;
+        }
+
+        LambdaQueryWrapper<KxStoreAppraise> lqw = new LambdaQueryWrapper<>();
+        lqw.in(KxStoreAppraise::getOrderId, orderIds);
+        lqw.eq(KxStoreAppraise::getState, 1); // 只统计已通过的评价
+        
+        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;
+        }
+        
+        // 计算统计数据
+        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;
+    }
+
+    @Override
+    public int replyAppraise(Long appraiseId, String replyContent, Long riderId) {
+        // 首先验证该评价是否属于该骑手配送的订单
+        List<Long> orderIds = getRiderOrderIds(riderId);
+        
+        KxStoreAppraise appraise = appraiseMapper.selectById(appraiseId);
+        if (appraise == null) {
+            throw new ServiceException("评价不存在");
+        }
+        
+        if (!orderIds.contains(appraise.getOrderId())) {
+            throw new ServiceException("无权限回复该评价");
+        }
+        
+        // 更新回复内容(这里假设有reply字段,如果没有需要扩展表结构)
+        // 注意:原始的KxStoreAppraise实体类可能需要添加reply和replyTime字段
+        KxStoreAppraise updateAppraise = new KxStoreAppraise();
+        updateAppraise.setId(appraiseId);
+        // updateAppraise.setReply(replyContent);  // 需要在实体类中添加该字段
+        // updateAppraise.setReplyTime(new Date()); // 需要在实体类中添加该字段
+        updateAppraise.setUpdateTime(new Date());
+        
+        return appraiseMapper.updateById(updateAppraise);
+    }
+
+    /**
+     * 获取骑手配送的所有订单ID
+     *
+     * @param riderId 骑手ID
+     * @return 订单ID列表
+     */
+    private List<Long> getRiderOrderIds(Long riderId) {
+        LambdaQueryWrapper<KxRiderOrder> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(KxRiderOrder::getRiderId, riderId);
+        wrapper.select(KxRiderOrder::getOrderId);
+
+        List<KxRiderOrder> riderOrders = riderOrderMapper.selectList(wrapper);
+        return riderOrders.stream()
+                .map(KxRiderOrder::getOrderId)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 构建查询条件
+     */
+    private LambdaQueryWrapper<KxStoreAppraise> buildQueryWrapper(KxStoreAppraiseBo bo) {
+        LambdaQueryWrapper<KxStoreAppraise> lqw = new LambdaQueryWrapper<>();
+        lqw.eq(bo.getProductId() != null, KxStoreAppraise::getProductId, bo.getProductId());
+        lqw.eq(bo.getProductAttrId() != null, KxStoreAppraise::getProductAttrId, bo.getProductAttrId());
+        lqw.eq(bo.getOrderId() != null, KxStoreAppraise::getOrderId, bo.getOrderId());
+        lqw.eq(bo.getUserId() != null, KxStoreAppraise::getUserId, bo.getUserId());
+        lqw.like(StringUtils.isNotBlank(bo.getContent()), KxStoreAppraise::getContent, bo.getContent());
+        lqw.eq(bo.getScore() != null, KxStoreAppraise::getScore, bo.getScore());
+        lqw.eq(bo.getState() != null, KxStoreAppraise::getState, bo.getState());
+        lqw.eq(bo.getStorageId() != null, KxStoreAppraise::getStorageId, bo.getStorageId());
+        return lqw;
+    }
+}

+ 13 - 28
kxmall-rider-api/src/main/java/com/kxmall/web/controller/task/TaskCenterController.java

@@ -33,47 +33,36 @@ public class TaskCenterController extends BaseRiderController {
      * @return 结果
      */
     @GetMapping("/list")
-    public TableDataInfo<KxRiderOrderVo> list(
-            Integer status,
-            Integer page,
-            Integer limit) {
+    public TableDataInfo<KxRiderOrderVo> list(Integer status, Integer page, Integer limit) {
         Long riderId = getRiderLoginUser().getUserId();
-        return taskCenterService.list(status,page,limit, riderId);
+        return taskCenterService.list(status, page, limit, riderId);
     }
 
 
-
     /**
      * 开始配送
      *
      * @return 结果
      */
     @GetMapping("/begin")
-    public R<String> begin(Long riderOrderId,
-                           BigDecimal lng,
-                           BigDecimal lat) {
+    public R<String> begin(Long riderOrderId, BigDecimal lng, BigDecimal lat) {
         Long riderId = getRiderLoginUser().getUserId();
-        return R.ok("操作成功",taskCenterService.begin(riderOrderId,lng,lat, riderId));
+        return R.ok("操作成功", taskCenterService.begin(riderOrderId, lng, lat, riderId));
     }
 
 
-
     /**
      * 异常配送
      *
      * @return 结果
      */
     @GetMapping("/abnormal")
-    public R<String> abnormal(Long riderOrderId,
-                              String reason,
-                              BigDecimal lng,
-                              BigDecimal lat) {
+    public R<String> abnormal(Long riderOrderId, String reason, BigDecimal lng, BigDecimal lat) {
         Long riderId = getRiderLoginUser().getUserId();
-        return R.ok("操作成功",taskCenterService.abnormal(riderOrderId,reason,lng,lat, riderId));
+        return R.ok("操作成功", taskCenterService.abnormal(riderOrderId, reason, lng, lat, riderId));
     }
 
 
-
     /**
      * 订单详情
      *
@@ -83,19 +72,18 @@ public class TaskCenterController extends BaseRiderController {
     @GetMapping("/detail")
     public R<KxRiderOrderVo> detail(Long riderOrderId) {
         Long riderId = getRiderLoginUser().getUserId();
-        return R.ok("操作成功!",taskCenterService.detail(riderOrderId, riderId));
+        return R.ok("操作成功!", taskCenterService.detail(riderOrderId, riderId));
     }
+
     /**
      * 完成配送
      *
      * @return 结果
      */
     @GetMapping("/complete")
-    public R<String> complete(Long riderOrderId,
-                                      BigDecimal lng,
-                                      BigDecimal lat) {
+    public R<String> complete(Long riderOrderId, BigDecimal lng, BigDecimal lat) {
         Long riderId = getRiderLoginUser().getUserId();
-        return R.ok("操作成功!",taskCenterService.complete(riderOrderId,lng,lat,riderId));
+        return R.ok("操作成功!", taskCenterService.complete(riderOrderId, lng, lat, riderId));
     }
 
     /**
@@ -106,25 +94,22 @@ public class TaskCenterController extends BaseRiderController {
     @GetMapping("/statistical")
     public R<RiderOrderStatisticalDTO> statistical() {
         Long riderId = getRiderLoginUser().getUserId();
-        return R.ok("操作成功!",taskCenterService.statistical(riderId));
+        return R.ok("操作成功!", taskCenterService.statistical(riderId));
     }
 
 
-
     /**
      * 收入列表
      *
      * @return 结果
      */
     @GetMapping("/income")
-    public TableDataInfo<KxRiderOrderVo> income(Integer pageNum,
-                                                Integer limit) {
+    public TableDataInfo<KxRiderOrderVo> income(Integer pageNum, Integer limit) {
         Long riderId = getRiderLoginUser().getUserId();
-        return taskCenterService.income(pageNum,limit,riderId);
+        return taskCenterService.income(pageNum, limit, riderId);
     }
 
 
-
     /**
      * 统计金额
      *

+ 81 - 0
kxmall-system/src/main/java/com/kxmall/order/domain/KxOrderScreenshot.java

@@ -0,0 +1,81 @@
+package com.kxmall.order.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 订单截图表
+ * </p>
+ *
+ * @author tea
+ * @since 2025-09-04
+ */
+@Getter
+@Setter
+@TableName("kx_order_screenshot")
+public class KxOrderScreenshot implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 截图ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 订单号
+     */
+    private String orderId;
+
+    /**
+     * (1:创建订单, 2:服务前, 3:服务中, 4:服务后, 5:问题反馈, 0:其他)
+     */
+    private Boolean screenshotType;
+
+    /**
+     * 图片URL
+     */
+    private String imageUrl;
+
+    /**
+     * 图片大小(字节)
+     */
+    private Long imageSize;
+
+    /**
+     * 上传时间
+     */
+    private LocalDateTime uploadTime;
+
+    /**
+     * 图片类型(1:用户、2:师傅、3:admin)
+     */
+    private Boolean userType;
+
+    /**
+     * 上传人
+     */
+    private Long uploadBy;
+
+    /**
+     * 排序顺序
+     */
+    private Integer sortOrder;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 是否删除
+     */
+    private Boolean isDeleted;
+}

+ 20 - 0
kxmall-system/src/main/java/com/kxmall/order/domain/bo/KxStoreAppraiseBo.java

@@ -64,4 +64,24 @@ public class KxStoreAppraiseBo extends BaseEntity {
      * 仓库权限参数
      */
     private Set<Long> storageIds;
+
+    /**
+     * 仓库id
+     */
+    private Long storageId;
+
+    /**
+     * 骑手ID(用于骑手查询自己配送订单的评价)
+     */
+    private Long riderId;
+
+    /**
+     * 最小评分(用于筛选)
+     */
+    private Long minRating;
+
+    /**
+     * 最大评分(用于筛选)
+     */
+    private Long maxRating;
 }

+ 2 - 0
kxmall-system/src/main/java/com/kxmall/order/domain/bo/OrderMessageBO.java

@@ -54,6 +54,8 @@ public class OrderMessageBO implements Serializable {
 
     /*** ==============订单信息===============*/
 
+    private Long orderId;
+
     // 订单编号
     private String orderNo;
 

+ 5 - 0
kxmall-system/src/main/java/com/kxmall/order/domain/bo/OrderRequestBo.java

@@ -91,4 +91,9 @@ public class OrderRequestBo {
      */
     private KxStoreCouponUser coupon;
 
+    /**
+     * 订单照片URL列表
+     */
+    private List<String> photos;
+
 }

+ 70 - 0
kxmall-system/src/main/java/com/kxmall/order/domain/vo/KxOrderScreenshotVo.java

@@ -0,0 +1,70 @@
+package com.kxmall.order.domain.vo;
+
+import java.time.LocalDateTime;
+import lombok.Data;
+
+/**
+ * 订单截图视图对象 kx_order_screenshot
+ *
+ * @author kxmall
+ * @date 2024-12-01
+ */
+@Data
+public class KxOrderScreenshotVo {
+
+    /**
+     * 截图ID
+     */
+    private Long id;
+
+    /**
+     * 订单号
+     */
+    private String orderId;
+
+    /**
+     * (1:创建订单, 2:服务前, 3:服务中, 4:服务后, 5:问题反馈, 0:其他)
+     */
+    private Boolean screenshotType;
+
+    /**
+     * 图片URL
+     */
+    private String imageUrl;
+
+    /**
+     * 图片大小(字节)
+     */
+    private Long imageSize;
+
+    /**
+     * 上传时间
+     */
+    private LocalDateTime uploadTime;
+
+    /**
+     * 图片类型(1:用户、2:师傅、3:admin)
+     */
+    private Boolean userType;
+
+    /**
+     * 上传人
+     */
+    private Long uploadBy;
+
+    /**
+     * 排序顺序
+     */
+    private Integer sortOrder;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 是否删除
+     */
+    private Boolean isDeleted;
+
+}

+ 15 - 0
kxmall-system/src/main/java/com/kxmall/order/mapper/KxOrderScreenshotMapper.java

@@ -0,0 +1,15 @@
+package com.kxmall.order.mapper;
+
+import com.kxmall.common.core.mapper.BaseMapperPlus;
+import com.kxmall.order.domain.KxOrderScreenshot;
+import com.kxmall.order.domain.vo.KxOrderScreenshotVo;
+
+/**
+ * 订单截图Mapper接口
+ *
+ * @author kxmall
+ * @date 2024-12-01
+ */
+public interface KxOrderScreenshotMapper extends BaseMapperPlus<KxOrderScreenshotMapper, KxOrderScreenshot, KxOrderScreenshotVo> {
+
+}

+ 6 - 0
kxmall-system/src/main/java/com/kxmall/rider/domain/KxRider.java

@@ -99,4 +99,10 @@ public class KxRider extends BaseEntity {
     private String accountHolder;
     private String idCardNumber;
 
+    private BigDecimal workRadio;
+
+    private Byte level;
+
+    private String workTypeKeywords;
+
 }

+ 21 - 0
kxmall-system/src/main/resources/mapper/order/KxOrderScreenshotMapper.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.kxmall.order.mapper.KxOrderScreenshotMapper">
+
+    <resultMap type="KxOrderScreenshot" id="KxOrderScreenshotResult">
+        <result property="id"    column="id"    />
+        <result property="orderId"    column="order_id"    />
+        <result property="screenshotType"    column="screenshot_type"    />
+        <result property="imageUrl"    column="image_url"    />
+        <result property="imageSize"    column="image_size"    />
+        <result property="uploadTime"    column="upload_time"    />
+        <result property="userType"    column="user_type"    />
+        <result property="uploadBy"    column="upload_by"    />
+        <result property="sortOrder"    column="sort_order"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="isDeleted"    column="is_deleted"    />
+    </resultMap>
+
+</mapper>

+ 7 - 6
需求列表.md

@@ -1,7 +1,7 @@
 # 个人中心
-- [ ] 个人 短信注册
-- [ ] 师傅 评价管理
-- [ ] 设置服务半径(如 5 公里内接单)、擅长服务类型,系统优先推送匹配订单 关联派单业务
+- [x] 个人 短信注册
+- [x] 师傅 评价管理
+- [x] 设置服务半径(如 5 公里内接单)、擅长服务类型,系统优先推送匹配订单 关联派单业务
 
 # 服务商品
 - [ ] 商品分类 查询条件(按销量、价格、评分筛选)
@@ -48,8 +48,9 @@
 
 # 平台
 - [ ] 收款码
-- [ ] 用户充值 师傅提现,提现至零钱,api:https://pay.weixin.qq.com/doc/v3/merchant/4012064660?from=https%3A%2F%2Fpay.weixin.qq.com%2Fdocs%2Fmerchant%2Fproducts%2Fbatch-transfer-to-balance%2Fintroduction.html#%E6%AD%A5%E9%AA%A42%EF%BC%9A%E5%85%85%E5%80%BC%E8%BF%90%E8%90%A5%E8%B4%A6%E6%88%B7
+- [x] 用户充值 师傅提现,提现至零钱,api:https://pay.weixin.qq.com/doc/v3/merchant/4012064660?from=https%3A%2F%2Fpay.weixin.qq.com%2Fdocs%2Fmerchant%2Fproducts%2Fbatch-transfer-to-balance%2Fintroduction.html#%E6%AD%A5%E9%AA%A42%EF%BC%9A%E5%85%85%E5%80%BC%E8%BF%90%E8%90%A5%E8%B4%A6%E6%88%B7
 
 # 系统bug
-- [ ] 订单客户信息有误
-- [ ] 师傅测订单状态异常
+- [x] 订单客户信息有误
+- [ ] 师傅测订单状态异常
+- [x] 退出登录清除余额等信息