已修改12个文件
已添加8个文件
857 ■■■■ 文件已修改
src/main/java/com/mzl/flower/dto/request/payment/OrderItemSalesQueryDTO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/dto/response/statistics/FlowerStatisticsDTO.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/dto/response/statistics/OrderStatisticsDTO.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/dto/response/statistics/RateStatisticsDTO.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/dto/response/statistics/SaleStatisticsDTO.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/entity/ip/UserAccess.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/mapper/ip/UserAccessMapper.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/mapper/payment/OrderItemMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/mapper/payment/OrderMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/schedule/ScheduleService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/service/payment/OrderItemSalesService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/service/register/RegisterService.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/service/statistics/StatisticsService.java 420 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/web/customer/FlowerCustomerController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/web/statistics/StatisticsController.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/payment/DeliveryOrderMapper.xml 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/payment/OrderItemMapper.xml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/payment/OrderItemSalesMapper.xml 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/payment/OrderMapper.xml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/system/MenuMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/mzl/flower/dto/request/payment/OrderItemSalesQueryDTO.java
@@ -5,6 +5,7 @@
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class OrderItemSalesQueryDTO implements Serializable {
@@ -69,4 +70,6 @@
    private LocalDateTime salesEndDate;
    private String salesType;//售后类型
    private List<String> statusList;
}
src/main/java/com/mzl/flower/dto/response/statistics/FlowerStatisticsDTO.java
对比新文件
@@ -0,0 +1,33 @@
package com.mzl.flower.dto.response.statistics;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class FlowerStatisticsDTO {
    @ApiModelProperty(value = "商品管理")
    private Long flowerCount;
    @ApiModelProperty(value = "供应商")
    private Long supplierCount;
    @ApiModelProperty(value = "用户管理")
    private Long customerCount;
    @ApiModelProperty(value = "订单管理")
    private Long orderCount;
    @ApiModelProperty(value = "订单管理-待发货")
    private Long orderSendCount;
    @ApiModelProperty(value = "商品管理-在售")
    private Long flowerUpCount;
    @ApiModelProperty(value = "商品管理-待审核")
    private Long flowerPendingCount;
    @ApiModelProperty(value = "待售后处理")
    private Long orderSalesCount;
}
src/main/java/com/mzl/flower/dto/response/statistics/OrderStatisticsDTO.java
对比新文件
@@ -0,0 +1,21 @@
package com.mzl.flower.dto.response.statistics;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class OrderStatisticsDTO {
    @ApiModelProperty(value = "总销售金额")
    private BigDecimal totalSaleAmount;
    @ApiModelProperty(value = "总销售扎数")
    private Long totalSaleFlowerCount;
    @ApiModelProperty(value = "供应商待提现")
    private BigDecimal supplierPendingAmount;
    @ApiModelProperty(value = "供应商已提现")
    private BigDecimal supplierCompleteAmount;
}
src/main/java/com/mzl/flower/dto/response/statistics/RateStatisticsDTO.java
对比新文件
@@ -0,0 +1,17 @@
package com.mzl.flower.dto.response.statistics;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class RateStatisticsDTO {
    @ApiModelProperty(value = "量")
    private Long count;
    @ApiModelProperty(value = "新增量")
    private Long countToday;
    @ApiModelProperty(value = "日环比")
    private Double countRate;
}
src/main/java/com/mzl/flower/dto/response/statistics/SaleStatisticsDTO.java
对比新文件
@@ -0,0 +1,15 @@
package com.mzl.flower.dto.response.statistics;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class SaleStatisticsDTO {
    @ApiModelProperty(value = "销售额")
    private BigDecimal saleAmount;
    @ApiModelProperty(value = "销售扎数")
    private Long saleFlowerCount;
}
src/main/java/com/mzl/flower/entity/ip/UserAccess.java
对比新文件
@@ -0,0 +1,21 @@
package com.mzl.flower.entity.ip;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("user_access_info")
public class UserAccess {
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    private String ipId; //    ip地址+用户ID
    private LocalDateTime createTime;
}
src/main/java/com/mzl/flower/mapper/ip/UserAccessMapper.java
对比新文件
@@ -0,0 +1,11 @@
package com.mzl.flower.mapper.ip;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mzl.flower.entity.ip.BlackList;
import com.mzl.flower.entity.ip.UserAccess;
import org.springframework.stereotype.Repository;
@Repository
public interface UserAccessMapper extends BaseMapper<UserAccess> {
}
src/main/java/com/mzl/flower/mapper/payment/OrderItemMapper.java
@@ -8,6 +8,7 @@
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
@Repository
@@ -17,4 +18,7 @@
    List<OrderItemPlatformListDTO> getPlatformOrderItems(@Param("orderId") String orderId);
    List<OrderItemListDTO> getOrderItems(@Param("orderIds") List<String> orderIds);
    Integer getFlowerSaleNum(@Param("startTime") LocalDateTime startTime
            , @Param("endTime") LocalDateTime endTime);
}
src/main/java/com/mzl/flower/mapper/payment/OrderMapper.java
@@ -9,6 +9,7 @@
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@@ -70,4 +71,6 @@
            ")")
    List<String> getWaitSendMessageInfoBySupplier(String Status, LocalDateTime startTime, LocalDateTime endTime);
    BigDecimal getOrderSaleAmount(@Param("startTime") LocalDateTime startTime
            , @Param("endTime") LocalDateTime endTime);
}
src/main/java/com/mzl/flower/schedule/ScheduleService.java
@@ -282,11 +282,11 @@
        LocalDateTime endDateTime = LocalDateTime.of(currentDate, LocalTime.of(17, 0));
        System.out.println("开始时间: " + startDateTime);
        System.out.println("结束时间: " + endDateTime);
        List<String> sends = orderMapper.getWaitSendMessageInfoBySupplier("SEND", startDateTime, endDateTime);
        List<String> sends = orderMapper.getWaitSendMessageInfoBySupplier("COLLECTION", startDateTime, endDateTime);
        if(CollectionUtils.isNotEmpty(sends)) {
            sends.forEach(s -> {
                try {
                    SmsUtil.sendSms(s, "SMS_474500141", null);
                    SmsUtil.sendSms(s, "SMS_474905508", null);
                } catch (ClientException e) {
                    log.error("发送短信失败,手机号:" + s, e);
                }
src/main/java/com/mzl/flower/service/payment/OrderItemSalesService.java
@@ -197,6 +197,7 @@
        dto.setOrderEndDate(parseLocalDateTime(dto.getOrderEndDateStr(), false));
        dto.setSalesStartDate(parseLocalDateTime(dto.getSalesStartDateStr(), true));
        dto.setSalesEndDate(parseLocalDateTime(dto.getSalesEndDateStr(), false));
        dto.setStatusList(splitParam(dto.getStatus()));
        List<OrderItemSalesNewListDTO> ls = orderItemSalesMapper.selectItemSalesList(page, dto);
@@ -209,6 +210,7 @@
        dto.setOrderEndDate(parseLocalDateTime(dto.getOrderEndDateStr(), false));
        dto.setSalesStartDate(parseLocalDateTime(dto.getSalesStartDateStr(), true));
        dto.setSalesEndDate(parseLocalDateTime(dto.getSalesEndDateStr(), false));
        dto.setStatusList(splitParam(dto.getStatus()));
        List<OrderItemSalesNewListDTO> ls = orderItemSalesMapper.selectItemSalesList(null, dto);
        codeDecorator.decorate(ls);
src/main/java/com/mzl/flower/service/register/RegisterService.java
@@ -1,7 +1,6 @@
package com.mzl.flower.service.register;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mzl.flower.config.exception.ValidationException;
import com.mzl.flower.constant.Constants;
import com.mzl.flower.dto.request.register.RegisterCustomerDTO;
@@ -13,6 +12,7 @@
import com.mzl.flower.mapper.system.UserWechatMapper;
import com.mzl.flower.service.customer.CustomerService;
import com.mzl.flower.service.partner.PartnerService;
import com.mzl.flower.service.payment.RedisLockService;
import com.mzl.flower.utils.UUIDGenerator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
@@ -36,15 +36,19 @@
    private final UserWechatMapper wechatMapper;
    private final RedisLockService lockService;
    public RegisterService(UserMapper userMapper,
                           PasswordEncoder passwordEncoder,
                           PartnerService partnerService,
                           CustomerService customerService, UserWechatMapper wechatMapper) {
                           CustomerService customerService, UserWechatMapper wechatMapper,
                           RedisLockService lockService) {
        this.userMapper = userMapper;
        this.passwordEncoder = passwordEncoder;
        this.partnerService = partnerService;
        this.customerService = customerService;
        this.wechatMapper = wechatMapper;
        this.lockService = lockService;
    }
    public void registerUser(RegisterDTO dto, String userType) {
@@ -65,39 +69,49 @@
    }
    public void registerCustomerUser(RegisterCustomerDTO dto, String userType, String openId, String sessionKey, String unionId) {
        if(checkUserExist(dto.getTel(),userType)){
            throw new ValidationException("该手机号码已经注册");
        String key = dto.getTel() + "_" + userType;
        boolean lock = lockService.getObjectLock(RedisLockService.LOCK_KEY_CART_, key);
        if(!lock){
            return;
        }
        User user = new User();
        user.setId(UUIDGenerator.getUUID());
        user.setLoginName(dto.getTel());
        user.setTel(dto.getTel());
        user.setNickName(dto.getTel());
        user.setPassword(passwordEncoder.encode(dto.getPassword()));
        user.setType(userType);
        user.setStatus(Constants.STATUS_ACTIVE);
        user.setIsSys(Constants.N);
        user.create();
        userMapper.insert(user);
        if(StringUtils.isNotBlank(openId)){
            UserWechat wechat = wechatMapper.selectOne(new LambdaQueryWrapper<UserWechat>()
                    .eq(UserWechat::getUserId,user.getId())
                    .eq(UserWechat::getOpenId,openId));
            if(wechat != null){
                throw new ValidationException("该微信用户已经注册");
        try {
            if(checkUserExist(dto.getTel(),userType)){
                throw new ValidationException("该手机号码已经注册");
            }
            wechat = new UserWechat();
            wechat.setUserId(user.getId());
            wechat.setId(UUIDGenerator.getUUID());
            wechat.setOpenId(openId);
            wechat.setUnionId(unionId);
            wechat.setSessionKey(sessionKey);
            wechat.create(user.getId());
            wechatMapper.insert(wechat);
            User user = new User();
            user.setId(UUIDGenerator.getUUID());
            user.setLoginName(dto.getTel());
            user.setTel(dto.getTel());
            user.setNickName(dto.getTel());
            user.setPassword(passwordEncoder.encode(dto.getPassword()));
            user.setType(userType);
            user.setStatus(Constants.STATUS_ACTIVE);
            user.setIsSys(Constants.N);
            user.create();
            userMapper.insert(user);
            if(StringUtils.isNotBlank(openId)){
                UserWechat wechat = wechatMapper.selectOne(new LambdaQueryWrapper<UserWechat>()
                        .eq(UserWechat::getUserId,user.getId())
                        .eq(UserWechat::getOpenId,openId));
                if(wechat != null){
                    throw new ValidationException("该微信用户已经注册");
                }
                wechat = new UserWechat();
                wechat.setUserId(user.getId());
                wechat.setId(UUIDGenerator.getUUID());
                wechat.setOpenId(openId);
                wechat.setUnionId(unionId);
                wechat.setSessionKey(sessionKey);
                wechat.create(user.getId());
                wechatMapper.insert(wechat);
            }
            dto.getDto().setUserId(user.getId());
            customerService.addOrUpdateCustomer(dto.getDto());
        }finally {
            lockService.releaseObjectLock(RedisLockService.LOCK_KEY_CART_, key);
        }
        dto.getDto().setUserId(user.getId());
        customerService.addOrUpdateCustomer(dto.getDto());
    }
src/main/java/com/mzl/flower/service/statistics/StatisticsService.java
对比新文件
@@ -0,0 +1,420 @@
package com.mzl.flower.service.statistics;
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.mzl.flower.config.exception.ValidationException;
import com.mzl.flower.config.security.SecurityUtils;
import com.mzl.flower.constant.Constants;
import com.mzl.flower.dto.request.flower.FlowerQueryDTO;
import com.mzl.flower.dto.request.payment.OrderItemSalesQueryDTO;
import com.mzl.flower.dto.request.payment.OrderQueryDTO;
import com.mzl.flower.dto.response.statistics.FlowerStatisticsDTO;
import com.mzl.flower.dto.response.statistics.OrderStatisticsDTO;
import com.mzl.flower.dto.response.statistics.RateStatisticsDTO;
import com.mzl.flower.dto.response.statistics.SaleStatisticsDTO;
import com.mzl.flower.entity.customer.Customer;
import com.mzl.flower.entity.ip.UserAccess;
import com.mzl.flower.entity.payment.Order;
import com.mzl.flower.entity.supplier.Supplier;
import com.mzl.flower.mapper.customer.CustomerMapper;
import com.mzl.flower.mapper.flower.FlowerMapper;
import com.mzl.flower.mapper.ip.UserAccessMapper;
import com.mzl.flower.mapper.payment.*;
import com.mzl.flower.mapper.supplier.SupplierMapper;
import com.mzl.flower.service.BaseService;
import com.mzl.flower.utils.IpUtil;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
@Transactional
public class StatisticsService extends BaseService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private FlowerMapper flowerMapper;
    @Autowired
    private SupplierMapper supplierMapper;
    @Autowired
    private OrderItemSalesMapper orderItemSalesMapper;
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private UserAccessMapper userAccessMapper;
    public SaleStatisticsDTO getSaleStatistics(String date){
        if(StringUtils.isEmpty(date)){
            throw new ValidationException("日期不能为空");
        }
        LocalDate localDate = parseLocalDate(date);
        if(localDate == null){
            throw new ValidationException("日期无效");
        }
        LocalDateTime end = localDate.atTime(17, 0, 0);
        LocalDateTime begin = end.plusDays(-1);
        SaleStatisticsDTO dto = new SaleStatisticsDTO();
        BigDecimal a = orderMapper.getOrderSaleAmount(begin, end);//今日销售额:今日全部的实际支付金额合计
        Integer c = orderItemMapper.getFlowerSaleNum(begin, end);//今日销售扎数:今日成功交易的订单的成交数量
        dto.setSaleAmount(a);
        dto.setSaleFlowerCount(c == null ? 0 : c.longValue());
        return dto;
    }
    public FlowerStatisticsDTO getFlowerStatistics(){
        FlowerStatisticsDTO dto = new FlowerStatisticsDTO();
        Page page = new Page(1, 1);
        FlowerQueryDTO q = new FlowerQueryDTO();
        List<String> statusList = new ArrayList<>();
        statusList.add(Constants.FLOWER_STATUS.PENDING.name());
        statusList.add(Constants.FLOWER_STATUS.UP.name());
        statusList.add(Constants.FLOWER_STATUS.OFF.name());
        statusList.add(Constants.FLOWER_STATUS.FORCE_OFF.name());
        q.setStatusList(statusList);
        flowerMapper.selectFlowerList(page, q);
        dto.setFlowerCount(page.getTotal());//商品管理:待审核+上架+下架(点击跳转到商品列表)
        Integer sc = supplierMapper.selectCount(new QueryWrapper<Supplier>()
                .eq("is_enabled", 1)
                .eq("status", "P")
                .eq("deleted", 0));
        dto.setSupplierCount(sc.longValue());
        Integer cc = customerMapper.selectCount(new QueryWrapper<Customer>()
                .eq("is_enabled", 1)
                .eq("deleted", 0));
        dto.setCustomerCount(cc.longValue());//用户管理:统计商户列表已启用的全部用户(点击跳转到商户列表)
        Integer oc = orderMapper.selectCount(new QueryWrapper<Order>()
                .eq("deleted", 0)
                .isNotNull("payment_time")
                .isNull("cancel_time")
                .isNull("refund_time"));
        dto.setOrderCount(oc.longValue());//订单管理:全部订单数量-待付款-已取消-已退款(点击跳转到订单列表)
        page = new Page(1, 1);
        OrderQueryDTO oq = new OrderQueryDTO();
        oq.setStatusBackend(Constants.ORDER_STATUS_BACKEND.SEND.name());
        orderMapper.selectOrderList(page, oq);
        dto.setOrderSendCount(page.getTotal());//待发货:统计订单列表待发货的数量(点击跳转到订单列表-待发货页面)
        page = new Page(1, 1);
        q = new FlowerQueryDTO();
        statusList = new ArrayList<>();
        statusList.add(Constants.FLOWER_STATUS.UP.name());
        q.setStatusList(statusList);
        flowerMapper.selectFlowerList(page, q);
        dto.setFlowerUpCount(page.getTotal());//在售商品:统计商品列表上架的商品数量(点击跳转到商品列表-上架页面)
        page = new Page(1, 1);
        q = new FlowerQueryDTO();
        statusList = new ArrayList<>();
        statusList.add(Constants.FLOWER_STATUS.PENDING.name());
        q.setStatusList(statusList);
        flowerMapper.selectFlowerList(page, q);
        dto.setFlowerPendingCount(page.getTotal());//待审核商品:跳转到商品列表-待审核页面
        page = new Page(1, 1);
        OrderItemSalesQueryDTO sq = new OrderItemSalesQueryDTO();
        sq.setStatus(Constants.ORDER_SALES_STATUS.PENDING.name());
        sq.setStatusList(splitParam(sq.getStatus()));
        orderItemSalesMapper.selectItemSalesList(page, sq);
        dto.setOrderSalesCount(page.getTotal());//待售后处理:统计售后理赔-待审核的数量(跳转到售后理赔-待审核页面)
        return dto;
    }
    public OrderStatisticsDTO getOrderStatistics(){
        OrderStatisticsDTO dto = new OrderStatisticsDTO();
        BigDecimal a = orderMapper.getOrderSaleAmount(null, null);//总销售金额:全部有效订单的实际支付金额合计
        Integer c = orderItemMapper.getFlowerSaleNum(null, null);//总销售扎数:成功交易订单的成交数量
        dto.setTotalSaleAmount(a);
        dto.setTotalSaleFlowerCount(c == null ? 0 : c.longValue());
        dto.setSupplierPendingAmount(new BigDecimal(0));//TODO 供应商待提现:结算列表待结算(供应商)+供应商钱包余额
        dto.setSupplierCompleteAmount(new BigDecimal(0));//TODO 供应商已提现:结算列表已结算(供应商)+供应商钱包已提现金额
        return dto;
    }
    public RateStatisticsDTO getOrderRateStatistics(String date){
        if(StringUtils.isEmpty(date)){
            throw new ValidationException("日期不能为空");
        }
        LocalDate localDate = parseLocalDate(date);
        if(localDate == null){
            throw new ValidationException("日期无效");
        }
        LocalDateTime end = localDate.atTime(17, 0, 0);
        LocalDateTime begin = end.plusDays(-1);
        LocalDateTime endY = begin;
        LocalDateTime beginY = endY.plusDays(-1);
        RateStatisticsDTO dto = new RateStatisticsDTO();
        //订单量:与订单管理一致(并计算新增量,计算日环比)
        Integer oc = orderMapper.selectCount(new QueryWrapper<Order>()
                .eq("deleted", 0)
                .isNotNull("payment_time")
                .isNull("cancel_time")
                .isNull("refund_time"));
        dto.setCount(oc.longValue());
        Integer ocToday = orderMapper.selectCount(new QueryWrapper<Order>()
                .eq("deleted", 0)
                .isNotNull("payment_time")
                .isNull("cancel_time")
                .isNull("refund_time")
                .gt("create_time", begin)
                .le("create_time", end)
        );
        dto.setCountToday(ocToday.longValue());
        Integer ocY = orderMapper.selectCount(new QueryWrapper<Order>()
                .eq("deleted", 0)
                .isNotNull("payment_time")
                .isNull("cancel_time")
                .isNull("refund_time")
                .gt("create_time", beginY)
                .le("create_time", endY)
        );
        dto.setCountRate(getRate(ocToday, ocY));
        return dto;
    }
    public RateStatisticsDTO getSupplierRateStatistics(String date) {
        if (StringUtils.isEmpty(date)) {
            throw new ValidationException("日期不能为空");
        }
        LocalDate localDate = parseLocalDate(date);
        if (localDate == null) {
            throw new ValidationException("日期无效");
        }
        LocalDateTime end = localDate.atTime(23, 59, 59);
        LocalDateTime begin = localDate.atTime(0, 0, 0);
        LocalDateTime endY = end.plusDays(-1);
        LocalDateTime beginY = begin.plusDays(-1);
        RateStatisticsDTO dto = new RateStatisticsDTO();
        //供应商数量:已启用的供应商数量(并计算新增量,计算日环比)
        Integer sc = supplierMapper.selectCount(new QueryWrapper<Supplier>()
                .eq("is_enabled", 1)
                .eq("status", "P")
                .eq("deleted", 0));
        dto.setCount(sc.longValue());
        Integer scT = supplierMapper.selectCount(new QueryWrapper<Supplier>()
                .eq("is_enabled", 1)
                .eq("status", "P")
                .eq("deleted", 0)
                .gt("create_time", begin)
                .le("create_time", end)
        );
        dto.setCountToday(scT.longValue());
        Integer scY = supplierMapper.selectCount(new QueryWrapper<Supplier>()
                .eq("is_enabled", 1)
                .eq("status", "P")
                .eq("deleted", 0)
                .gt("create_time", beginY)
                .le("create_time", endY)
        );
        dto.setCountRate(getRate(scT, scY));
        return dto;
    }
    public RateStatisticsDTO getCustomerRateStatistics(String date) {
        if (StringUtils.isEmpty(date)) {
            throw new ValidationException("日期不能为空");
        }
        LocalDate localDate = parseLocalDate(date);
        if (localDate == null) {
            throw new ValidationException("日期无效");
        }
        LocalDateTime end = localDate.atTime(23, 59, 59);
        LocalDateTime begin = localDate.atTime(0, 0, 0);
        LocalDateTime endY = end.plusDays(-1);
        LocalDateTime beginY = begin.plusDays(-1);
        RateStatisticsDTO dto = new RateStatisticsDTO();
        //全部用户量:已启用的用户数量合计(并计算新增量,计算日环比)
        Integer c = customerMapper.selectCount(new QueryWrapper<Customer>()
                .eq("deleted", 0));
        dto.setCount(c.longValue());
        Integer cT = customerMapper.selectCount(new QueryWrapper<Customer>()
                .eq("deleted", 0)
                .gt("create_time", begin)
                .le("create_time", end)
        );
        dto.setCountToday(cT.longValue());
        Integer cY = customerMapper.selectCount(new QueryWrapper<Customer>()
                .eq("deleted", 0)
                .gt("create_time", beginY)
                .le("create_time", endY)
        );
        dto.setCountRate(getRate(cT, cY));
        return dto;
    }
    public RateStatisticsDTO getCustomerVisitRateStatistics(String date) {
        if (StringUtils.isEmpty(date)) {
            throw new ValidationException("日期不能为空");
        }
        LocalDate localDate = parseLocalDate(date);
        if (localDate == null) {
            throw new ValidationException("日期无效");
        }
        LocalDateTime end = localDate.atTime(23, 59, 59);
        LocalDateTime begin = localDate.atTime(0, 0, 0);
        LocalDateTime endY = end.plusDays(-1);
        LocalDateTime beginY = begin.plusDays(-1);
        RateStatisticsDTO dto = new RateStatisticsDTO();
        //用户访问量:点击到交易大厅或者商品详情页面计算,同一个用户,每天只计算一次(包含游客)(并计算新增量,计算日环比)
        Integer c = userAccessMapper.selectCount(new QueryWrapper<UserAccess>());
        dto.setCount(c.longValue());
        Integer cT = userAccessMapper.selectCount(new QueryWrapper<UserAccess>()
                .gt("create_time", begin)
                .le("create_time", end)
        );
        dto.setCountToday(cT.longValue());
        Integer cY = userAccessMapper.selectCount(new QueryWrapper<UserAccess>()
                .gt("create_time", beginY)
                .le("create_time", endY)
        );
        dto.setCountRate(getRate(cT, cY));
        return dto;
    }
    public RateStatisticsDTO getSalesRateStatistics(String date) {
        if (StringUtils.isEmpty(date)) {
            throw new ValidationException("日期不能为空");
        }
        LocalDate localDate = parseLocalDate(date);
        if (localDate == null) {
            throw new ValidationException("日期无效");
        }
        LocalDateTime end = localDate.atTime(23, 59, 59);
        LocalDateTime begin = localDate.atTime(0, 0, 0);
        LocalDateTime endY = end.plusDays(-1);
        LocalDateTime beginY = begin.plusDays(-1);
        RateStatisticsDTO dto = new RateStatisticsDTO();
        //售后订单数量:统计待审核+已通过(并计算新增量,计算日环比)
        List<String> statusList = new ArrayList<>();
        statusList.add(Constants.ORDER_SALES_STATUS.PENDING.name());
        statusList.add(Constants.ORDER_SALES_STATUS.AGREED.name());
        Page page = new Page(1, 1);
        OrderItemSalesQueryDTO sq = new OrderItemSalesQueryDTO();
        sq.setStatusList(statusList);
        orderItemSalesMapper.selectItemSalesList(page, sq);
        dto.setCount(page.getTotal());
        page = new Page(1, 1);
        sq = new OrderItemSalesQueryDTO();
        sq.setStatusList(statusList);
        sq.setSalesStartDate(begin);
        sq.setSalesStartDate(end);
        orderItemSalesMapper.selectItemSalesList(page, sq);
        dto.setCountToday(page.getTotal());
        page = new Page(1, 1);
        sq = new OrderItemSalesQueryDTO();
        sq.setStatusList(statusList);
        sq.setSalesStartDate(beginY);
        sq.setSalesStartDate(endY);
        orderItemSalesMapper.selectItemSalesList(page, sq);
        dto.setCountRate(getRate(dto.getCountToday().intValue(), (int)page.getTotal()));
        return dto;
    }
    private Double getRate(Integer today, Integer yesterday){
        if(yesterday > 0){
            Integer ty = today - yesterday;
            BigDecimal ttyy = BigDecimal.valueOf(ty);
            BigDecimal yy = BigDecimal.valueOf(yesterday);
            BigDecimal rate = ttyy.divide(yy, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
            return rate.doubleValue();
        } else if (today <= 0) {
            return 0D;
        }
        return 100D;
    }
    public void addUserAccessRecord(HttpServletRequest request){
        String userId = SecurityUtils.getUserId();
        String ip = null;
        try {
            ip = IpUtil.getIpAddress(request);
        } catch (IOException e) {
            ip = "127.0.0.1";
        }
        String ipId = ip+":"+(StringUtils.isBlank(userId)?"0":userId);
        LocalDate localDate = LocalDate.now();
        LocalDateTime end = localDate.atTime(23, 59, 59);
        LocalDateTime begin = localDate.atTime(0, 0, 0);
        int count = userAccessMapper.selectCount(new LambdaQueryWrapper<UserAccess>()
                .eq(UserAccess::getIpId, ipId)
                .gt(UserAccess::getCreateTime, begin)
                .le(UserAccess::getCreateTime, end));
        if(count==0){
            UserAccess record = new UserAccess();
            record.setIpId(ipId);
            record.setCreateTime(LocalDateTime.now());
            userAccessMapper.insert(record);
        }
    }
}
src/main/java/com/mzl/flower/web/customer/FlowerCustomerController.java
@@ -19,6 +19,7 @@
import com.mzl.flower.service.flower.FlowerParamService;
import com.mzl.flower.service.flower.FlowerService;
import com.mzl.flower.service.payment.OrderService;
import com.mzl.flower.service.statistics.StatisticsService;
import com.mzl.flower.service.transport.TransportService;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
@@ -32,6 +33,7 @@
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;
import javax.validation.constraints.NotBlank;
import java.util.HashMap;
@@ -59,10 +61,13 @@
    @Autowired
    private TransportService transportService;
    @Autowired
    private StatisticsService statisticsService;
    @GetMapping("/category/tree")
    @ApiOperation(value = "获取商品分类树")
    public ResponseEntity<ReturnDataDTO<List<FlowerCategoryTreeDTO>>> selectCategoryTree(FlowerCategoryQueryDTO dto){
    public ResponseEntity<ReturnDataDTO<List<FlowerCategoryTreeDTO>>> selectCategoryTree(FlowerCategoryQueryDTO dto, HttpServletRequest request){
        statisticsService.addUserAccessRecord(request);
        return returnData(R.SUCCESS.getCode(), categoryService.selectCustomerCategoryTree(dto));
    }
@@ -97,7 +102,8 @@
            @ApiImplicitParam(name = "id", value = "商品id", required = true, dataType = "Long", paramType = "query"),
            @ApiImplicitParam(name = "partnerId", value = "合伙人id", required = true, dataType = "Long", paramType = "query"),
    })
    public ResponseEntity<ReturnDataDTO<FlowerShowDTO>> getShowFlowerDetail(Long id, Long partnerId) {
    public ResponseEntity<ReturnDataDTO<FlowerShowDTO>> getShowFlowerDetail(Long id, Long partnerId,HttpServletRequest request) {
        statisticsService.addUserAccessRecord(request);
        return returnData(R.SUCCESS.getCode(), flowerService.getShowFlowerDetail(id, partnerId));
    }
src/main/java/com/mzl/flower/web/statistics/StatisticsController.java
对比新文件
@@ -0,0 +1,87 @@
package com.mzl.flower.web.statistics;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mzl.flower.base.BaseController;
import com.mzl.flower.base.R;
import com.mzl.flower.base.ReturnDataDTO;
import com.mzl.flower.dto.response.statistics.FlowerStatisticsDTO;
import com.mzl.flower.dto.response.statistics.OrderStatisticsDTO;
import com.mzl.flower.dto.response.statistics.RateStatisticsDTO;
import com.mzl.flower.dto.response.statistics.SaleStatisticsDTO;
import com.mzl.flower.service.statistics.StatisticsService;
import com.mzl.flower.utils.HttpUtil;
import com.wechat.pay.java.core.http.HttpMethod;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
@RestController
@RequestMapping("/api/statistics")
@Api(value = "统计", tags = "统计")
@Validated
@Slf4j
public class StatisticsController extends BaseController {
    @Autowired
    private StatisticsService statisticsService;
    @GetMapping("/sale/date")
    @ApiOperation(value = "当日销售统计")
    public ResponseEntity<ReturnDataDTO<SaleStatisticsDTO>> getSaleStatistics(String date){
        return returnData(R.SUCCESS.getCode(), statisticsService.getSaleStatistics(date));
    }
    @GetMapping("/flower/count")
    @ApiOperation(value = "商品商户统计")
    public ResponseEntity<ReturnDataDTO<FlowerStatisticsDTO>> getFlowerStatistics(){
        return returnData(R.SUCCESS.getCode(), statisticsService.getFlowerStatistics());
    }
    @GetMapping("/order/amount")
    @ApiOperation(value = "订单金额统计")
    public ResponseEntity<ReturnDataDTO<OrderStatisticsDTO>> getOrderStatistics(){
        return returnData(R.SUCCESS.getCode(), statisticsService.getOrderStatistics());
    }
    @GetMapping("/order/rate")
    @ApiOperation(value = "订单环比统计")
    public ResponseEntity<ReturnDataDTO<RateStatisticsDTO>> getOrderRateStatistics(String date){
        return returnData(R.SUCCESS.getCode(), statisticsService.getOrderRateStatistics(date));
    }
    @GetMapping("/supplier/rate")
    @ApiOperation(value = "商户环比统计")
    public ResponseEntity<ReturnDataDTO<RateStatisticsDTO>> getSupplierRateStatistics(String date){
        return returnData(R.SUCCESS.getCode(), statisticsService.getSupplierRateStatistics(date));
    }
    @GetMapping("/customer/rate")
    @ApiOperation(value = "花店环比统计")
    public ResponseEntity<ReturnDataDTO<RateStatisticsDTO>> getCustomerRateStatistics(String date){
        return returnData(R.SUCCESS.getCode(), statisticsService.getCustomerRateStatistics(date));
    }
    @GetMapping("/customer/visit/rate")
    @ApiOperation(value = "花店访问环比统计")
    public ResponseEntity<ReturnDataDTO<RateStatisticsDTO>> getCustomerVisitRateStatistics(String date){
        return returnData(R.SUCCESS.getCode(), statisticsService.getCustomerVisitRateStatistics(date));
    }
    @GetMapping("/sales/rate")
    @ApiOperation(value = "售后环比统计")
    public ResponseEntity<ReturnDataDTO<RateStatisticsDTO>> getSalesRateStatistics(String date){
        return returnData(R.SUCCESS.getCode(), statisticsService.getSalesRateStatistics(date));
    }
}
src/main/resources/mapper/payment/DeliveryOrderMapper.xml
@@ -188,61 +188,45 @@
    </select>
    <select id="statisticStationList" resultType="com.mzl.flower.dto.response.flower.StationStatisticDTO">
        select tt.*
            , (select count(distinct s.id)
                from t_supplier_info s
                join t_delivery_order q on s.id = q.supplier_id
                WHERE q.deleted = 0
                and q.status in ('CHECKED')
                AND s.station_id = tt.stationId
            ) checkedSupplierCount
            , (select count(distinct s.id)
                from t_supplier_info s
                join t_delivery_order q on s.id = q.supplier_id
                WHERE q.deleted = 0
                and q.status in ('PENDING', 'ARRIVED')
                AND s.station_id = tt.stationId
            ) uncheckedSupplierCount
        from (
            SELECT
                s.station_id AS stationId,
                st.`name`,
                SUM( oi.num ) AS totalNum
            FROM
            t_delivery_order o
            LEFT JOIN t_delivery_order_item i ON o.id = i.delivery_id
            LEFT JOIN t_order_item oi ON oi.id = i.order_item_id
            LEFT JOIN t_supplier_info s ON s.id = o.supplier_id
            LEFT JOIN t_station st ON st.id = s.station_id
            LEFT JOIN t_order t ON t.id = i.order_id
            WHERE o.deleted = 0
            AND o.`status` IN ( 'PENDING', 'ARRIVED', 'CHECKED' )
            <if test="userId !=null and userId !=''">
                AND st.user_ids LIKE concat('%', #{userId},'%')
            </if>
            <if test="name !=null and name !=''">
                AND ( s.id LIKE concat('%', #{name},'%')  OR
                      s.contact_tel LIKE concat('%', #{name},'%') OR
                      s.`name` LIKE concat('%', #{name},'%') OR
                      st.`name` LIKE concat('%', #{name},'%') OR
                      t.warehouse_location_code LIKE concat('%', #{name},'%')
                    )
            </if>
            <if test="startDate != null">
                AND o.create_time &gt; #{startDate}
            </if>
            <if test="endDate != null">
                AND o.create_time &lt;= #{endDate}
            </if>
        SELECT
        s.station_id AS stationId,
        st.`name`,
        SUM( oi.num ) AS totalNum,
        SUM(CASE WHEN  o.`status` = 'CHECKED'  THEN oi.num ELSE 0 END) AS checkedSupplierCount,
        SUM(CASE WHEN  o.`status` = 'PENDING' or o.`status`= 'ARRIVED' THEN oi.num ELSE 0 END) AS uncheckedSupplierCount
        FROM t_delivery_order o
        LEFT JOIN t_delivery_order_item i ON o.id = i.delivery_id
        LEFT JOIN t_order_item oi ON oi.id = i.order_item_id
        LEFT JOIN t_supplier_info s ON s.id = o.supplier_id
        LEFT JOIN t_station st ON st.id = s.station_id
        LEFT JOIN t_order t ON t.id = i.order_id
        WHERE o.deleted = 0
        AND o.`status` IN ( 'PENDING', 'ARRIVED', 'CHECKED' )
        <if test="userId !=null and userId !=''">
            AND st.user_ids LIKE concat('%', #{userId},'%')
        </if>
        <if test="name !=null and name !=''">
            AND ( s.id LIKE concat('%', #{name},'%')  OR
            s.contact_tel LIKE concat('%', #{name},'%') OR
            s.`name` LIKE concat('%', #{name},'%') OR
            st.`name` LIKE concat('%', #{name},'%') OR
            t.warehouse_location_code LIKE concat('%', #{name},'%')
            )
        </if>
        <if test="startDate != null">
            AND o.create_time &gt; #{startDate}
        </if>
        <if test="endDate != null">
            AND o.create_time &lt;= #{endDate}
        </if>
            <if test="statusList != null and statusList.size > 0">
                AND o.status in
                <foreach collection="statusList" item="status" open="(" separator="," close=")">
                    #{status}
                </foreach>
            </if>
            GROUP BY s.station_id, st.`name`
        ) tt
        <if test="statusList != null and statusList.size > 0">
            AND o.status in
            <foreach collection="statusList" item="status" open="(" separator="," close=")">
                #{status}
            </foreach>
        </if>
        GROUP BY s.station_id, st.`name`
    </select>
    <update id="setDeliveryOrderPending">
src/main/resources/mapper/payment/OrderItemMapper.xml
@@ -71,4 +71,18 @@
            #{orderId}
        </foreach>
    </select>
    <select id="getFlowerSaleNum" resultType="java.lang.Integer">
        SELECT sum(oi.num)
        FROM t_order_item oi
        JOIN t_order o on oi.order_id = o.id
        WHERE o.payment_time is not null
        and o.refund_time is null
        <if test="startTime != null">
            and o.create_time &gt; #{startTime}
        </if>
        <if test="endTime != null">
            and o.create_time &lt;= #{endTime}
        </if>
    </select>
</mapper>
src/main/resources/mapper/payment/OrderItemSalesMapper.xml
@@ -123,8 +123,11 @@
            AND si.create_time &lt;= #{condition.salesEndDate}
        </if>
        <if test="condition.status != null and condition.status != ''">
            AND si.status = #{condition.status}
        <if test="condition.statusList != null and condition.statusList.size > 0">
            AND si.status in
            <foreach collection="condition.statusList" item="item" open="(" separator="," close=")">
                #{item}
            </foreach>
        </if>
        <if test="condition.createBy != null and condition.createBy != ''">
src/main/resources/mapper/payment/OrderMapper.xml
@@ -362,4 +362,17 @@
        </if>
        ORDER BY q.create_time desc, q.payment_time desc
    </select>
    <select id="getOrderSaleAmount" resultType="java.math.BigDecimal">
        SELECT sum(o.payment_amount)
        FROM t_order o
        WHERE o.payment_time is not null
        and o.refund_time is null
        <if test="startTime != null">
            and o.create_time &gt; #{startTime}
        </if>
        <if test="endTime != null">
            and o.create_time &lt;= #{endTime}
        </if>
    </select>
</mapper>
src/main/resources/mapper/system/MenuMapper.xml
@@ -18,7 +18,7 @@
    </select>
    <select id="selectOperationList" resultType="com.mzl.flower.dto.response.system.MenuTreeDTO">
        SELECT m.ID AS id, PARENT_ID AS parentId, NAME AS menuName, TYPE AS type
        SELECT DISTINCT m.ID AS id, PARENT_ID AS parentId, NAME AS menuName, TYPE AS type
            , ICON AS menuIcon, keepAlive, HREF AS menuHref, SEQ AS seq
        FROM t_menu m
        JOIN t_role_menu rm ON m.ID = rm.MENU_ID