luodangjia
2024-08-19 61d43492bd055f354b586a15f97ea094fe9bf220
Merge remote-tracking branch 'origin/master'
76个文件已修改
18个文件已添加
4381 ■■■■ 已修改文件
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/UpdatePhoneDTO.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/factory/AppUserFallbackFactory.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/feignClient/AppUserClient.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TInvoiceInformation.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TChargingPileNotification.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteInfoVO.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TAccountingStrategyVO.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TOrderInvoice.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TActivity.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TAdvertising.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TCoupon.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TInvoiceType.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TNotice.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TVip.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/InvoiceTypeFallbackFactory.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/InvoiceTypeClient.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-auth/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-auth/src/main/java/com/ruoyi/auth/controller/TokenController.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/MsgConstants.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/HttpUtils.java 311 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MD5Util.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MsgUtil.java 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/req/SubmitTempletReq.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/BaseDelete.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/RuoYiGatewayApplication.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/CaptchaConfig.java 135 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/KaptchaTextCreator.java 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/RouterFunctionConfiguration.java 99 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/SwaggerProvider.java 113 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/CaptchaProperties.java 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/IgnoreWhiteProperties.java 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/XssProperties.java 60 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java 192 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java 91 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/CacheRequestFilter.java 122 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/HMACSHA1.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/RequestParamGlobalFilter.java 102 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/SignFilter.java 288 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java 172 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SwaggerHandler.java 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java 168 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppCouponController.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserController.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TInvoiceInformationController.java 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/TAppUserService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/TAppUserServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/resources/mapper/account/TInvoiceInformationMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/CodeController.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TCarportController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TFaultMessageController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TMonitoringEquipmentController.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TParkingLotController.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TVehicleRampController.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileNotificationService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TFaultMessageService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileNotificationServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TFaultMessageServiceImpl.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TMonitoringEquipmentServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TExchangeOrderController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TOrderInvoiceController.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TShoppingOrderController.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/AddOrderInvoice.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/GetMyShoppingOrderList.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/GetNoInvoicedOrder.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/GetOrderInvoiceList.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyOrderInvoiceInfo.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyShoppingOrderInfo.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyShoppingOrderList.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/OrderInvoiceList.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TShoppingOrderMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TOrderInvoiceService.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TShoppingOrderService.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TOrderInvoiceServiceImpl.java 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TShoppingOrderServiceImpl.java 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TOrderInvoiceMapper.xml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TShoppingOrderMapper.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TAdvertisingController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TInvoiceTypeController.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/UpdatePhoneDTO.java
New file
@@ -0,0 +1,22 @@
package com.ruoyi.account.api.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
@ApiModel(value = "UpdatePhoneDTO对象",description = "更换手机号DTO")
public class UpdatePhoneDTO implements Serializable {
    @ApiModelProperty(value = "手机号")
    @NotBlank(message = "手机号不能为空")
    private String phone;
    @ApiModelProperty(value = "验证码")
    @NotBlank(message = "验证码不能为空")
    private String code;
}
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/factory/AppUserFallbackFactory.java
@@ -41,6 +41,11 @@
            }
            @Override
            public R<TAppUser> selectByPhone(String phone) {
                return R.fail("通过手机号查询用户失败:"+throwable.getMessage());
            }
            @Override
            public R<List<TAppUser>> getUserByIds(List<Long> appUserIds) {
                return R.fail("根据用户id查询用户信息失败:"+throwable.getMessage());
            }
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/feignClient/AppUserClient.java
@@ -39,6 +39,14 @@
    
    
    
    @PostMapping("/t-app-user//user/updateAppUser")
    @PostMapping("/t-app-user/user/updateAppUser")
    R updateAppUser(@RequestBody TAppUser appUser);
    /**
     * 通过手机号查询用户
     * @param phone
     * @return
     */
    @GetMapping("/t-app-user/user/selectByPhone")
    R<TAppUser> selectByPhone(@RequestParam("phone") String phone);
}
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TInvoiceInformation.java
@@ -68,9 +68,9 @@
    @TableField("bank_account")
    private String bankAccount;
//    @ApiModelProperty(value = "设置默认(0=否,1=是)")
//    @TableField("default")
//    private Integer default;
    @ApiModelProperty(value = "设置默认(0=否,1=是)")
    @TableField("is_default")
    private Integer isDefault;
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/model/TChargingPileNotification.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -24,7 +25,7 @@
@EqualsAndHashCode(callSuper = false)
@TableName("t_charging_pile_notification")
@ApiModel(value="TChargingPileNotification对象", description="")
public class TChargingPileNotification implements Serializable {
public class TChargingPileNotification extends BasePojo {
    private static final long serialVersionUID = 1L;
@@ -51,15 +52,5 @@
    @ApiModelProperty(value = "通知内容")
    @TableField("content")
    private String content;
    @ApiModelProperty(value = "发送时间")
    @TableField("create_time")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "删除状态(0=否,1=是)")
    @TableField("del_flag")
    @TableLogic
    private Integer delFlag;
}
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/SiteInfoVO.java
@@ -18,6 +18,10 @@
    private BigDecimal electrovalence;
    @ApiModelProperty(value = "会员电价")
    private BigDecimal vipElectrovalence;
    @ApiModelProperty(value = "开通会员预计可省")
    private BigDecimal money;
    @ApiModelProperty(value = "额外赠送优惠券X张")
    private Integer couponCount;
    @ApiModelProperty(value = "超时占位费说明")
    private String spaceChargeExplain;
ruoyi-api/ruoyi-api-chargingPile/src/main/java/com/ruoyi/chargingPile/api/vo/TAccountingStrategyVO.java
@@ -16,4 +16,11 @@
    @ApiModelProperty(value = "计费策略明细集合")
    private List<TAccountingStrategyDetail> accountingStrategyDetailList;
    @ApiModelProperty(value = "一級审核人员")
    private String firstUserName;
    @ApiModelProperty(value = "二級审核人员")
    private String twoUserName;
}
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/model/TOrderInvoice.java
@@ -11,6 +11,7 @@
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * <p>
@@ -47,10 +48,14 @@
    @ApiModelProperty(value = "开票公司")
    @TableField("invoicing_company")
    private String invoicingCompany;
    @ApiModelProperty(value = "发票类型id")
    @TableField("invoice_type_id")
    private Integer invoiceTypeId;
    @ApiModelProperty(value = "发票类型(1=增值税普通发票,2=增值税专用发票)")
    @ApiModelProperty(value = "发票类型")
    @TableField("invoice_type")
    private Integer invoiceType;
    private String invoiceType;
    @ApiModelProperty(value = "发票材质(1=纸质发票,2=电子发票)")
    @TableField("invoice_material")
@@ -103,6 +108,17 @@
    @ApiModelProperty(value = "状态(1=待开票,2=开票中,3=已开票)")
    @TableField("status")
    private Integer status;
    @ApiModelProperty(value = "添加时间")
    @TableField("create_time")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "开票时间")
    @TableField("billing_time")
    private LocalDateTime billingTime;
    @ApiModelProperty(value = "开票人id")
    @TableField("billing_user_id")
    private Integer billingUserId;
}
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TActivity.java
@@ -1,6 +1,7 @@
package com.ruoyi.other.api.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -40,10 +41,12 @@
    @ApiModelProperty(value = "开始时间")
    @TableField("start_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime startTime;
    @ApiModelProperty(value = "结束时间")
    @TableField("end_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime endTime;
    @ApiModelProperty(value = "跳转类型(1=小程序内页面,2=小程序地址,3=网页地址)")
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TAdvertising.java
@@ -1,6 +1,7 @@
package com.ruoyi.other.api.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -40,10 +41,12 @@
    @ApiModelProperty(value = "开始时间")
    @TableField("start_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime startTime;
    @ApiModelProperty(value = "结束时间")
    @TableField("end_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime endTime;
    @ApiModelProperty(value = "显示位置(1=banner广告,2=弹出广告)")
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TCoupon.java
@@ -1,6 +1,7 @@
package com.ruoyi.other.api.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -77,6 +78,7 @@
    @ApiModelProperty(value = "使用截止时间")
    @TableField("end_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime endTime;
    @ApiModelProperty(value = "获取后有效天数")
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TInvoiceType.java
@@ -8,6 +8,7 @@
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
@@ -44,15 +45,15 @@
    @ApiModelProperty(value = "电费税率")
    @TableField("electricity_tariff")
    private Double electricityTariff;
    private BigDecimal electricityTariff;
    @ApiModelProperty(value = "服务费税率")
    @TableField("service_tariff")
    private Double serviceTariff;
    private BigDecimal serviceTariff;
    @ApiModelProperty(value = "增值服务费税率")
    @TableField("added_service_tariff")
    private Double addedServiceTariff;
    private BigDecimal addedServiceTariff;
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TNotice.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -39,10 +40,12 @@
    @ApiModelProperty(value = "开始时间")
    @TableField("start_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime startTime;
    @ApiModelProperty(value = "结束时间")
    @TableField("end_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime endTime;
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TVip.java
@@ -1,6 +1,7 @@
package com.ruoyi.other.api.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.core.web.domain.BasePojo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -53,10 +54,12 @@
    @ApiModelProperty(value = "月卡折扣开始时间")
    @TableField("monthly_card_discount_start")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime monthlyCardDiscountStart;
    @ApiModelProperty(value = "月卡折扣结束时间")
    @TableField("monthly_card_discount_end")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime monthlyCardDiscountEnd;
    @ApiModelProperty(value = "月卡折扣显示(0=否,1=是)")
@@ -77,10 +80,12 @@
    @ApiModelProperty(value = "季卡折扣开始时间")
    @TableField("season_card_discount_start")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime seasonCardDiscountStart;
    @ApiModelProperty(value = "季卡折扣结束时间")
    @TableField("season_card_discount_end")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime seasonCardDiscountEnd;
    @ApiModelProperty(value = "季卡折扣显示(0=否,1=是)")
@@ -101,10 +106,12 @@
    @ApiModelProperty(value = "年卡折扣开始时间")
    @TableField("annual_card_discount_start")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime annualCardDiscountStart;
    @ApiModelProperty(value = "年卡折扣结束时间")
    @TableField("annual_card_discount_end")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private LocalDateTime annualCardDiscountEnd;
    @ApiModelProperty(value = "年卡折扣显示(0=否,1=是)")
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/InvoiceTypeFallbackFactory.java
New file
@@ -0,0 +1,34 @@
package com.ruoyi.other.api.factory;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.other.api.domain.TInvoiceType;
import com.ruoyi.other.api.feignClient.InvoiceTypeClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
/**
 * 商品服务降级处理
 *
 * @author ruoyi
 */
@Component
public class InvoiceTypeFallbackFactory implements FallbackFactory<InvoiceTypeClient>
{
    private static final Logger log = LoggerFactory.getLogger(InvoiceTypeFallbackFactory.class);
    @Override
    public InvoiceTypeClient create(Throwable throwable) {
        log.error("开票类型失败:{}", throwable.getMessage());
        return new InvoiceTypeClient() {
            @Override
            public R<TInvoiceType> getInvoiceType(Integer id) {
                throw new RuntimeException(throwable.getMessage());
            }
        };
    }
}
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/InvoiceTypeClient.java
New file
@@ -0,0 +1,26 @@
package com.ruoyi.other.api.feignClient;
import com.ruoyi.common.core.constant.ServiceNameConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.other.api.domain.TInvoiceType;
import com.ruoyi.other.api.factory.InvoiceTypeFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
/**
 * @author zhibing.pu
 * @Date 2024/8/19 15:57
 */
@FeignClient(contextId = "IntegralRuleClient", value = ServiceNameConstants.OTHER_SERVICE, fallbackFactory = InvoiceTypeFallbackFactory.class)
public interface InvoiceTypeClient {
    /**
     * 根据id获取发票类型
     * @param id
     * @return
     */
    @PostMapping("/t-invoice-type/getInvoiceType/{id}")
    R<TInvoiceType> getInvoiceType(@PathVariable("id") Integer id);
}
ruoyi-api/ruoyi-api-other/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -5,4 +5,5 @@
com.ruoyi.other.api.factory.VipFallbackFactory
com.ruoyi.other.api.factory.IntegralRuleFallbackFactory
com.ruoyi.other.api.factory.GoodsFallbackFactory
com.ruoyi.other.api.factory.CouponFallbackFactory
com.ruoyi.other.api.factory.CouponFallbackFactory
com.ruoyi.other.api.factory.InvoiceTypeFallbackFactory
ruoyi-auth/pom.xml
@@ -85,6 +85,12 @@
            <version>${hutool.version}</version>
        </dependency>
        <dependency>
            <groupId>com.ruoyi</groupId>
            <artifactId>ruoyi-api-account</artifactId>
            <version>3.6.2</version>
        </dependency>
    </dependencies>
    
    <build>
ruoyi-auth/src/main/java/com/ruoyi/auth/controller/TokenController.java
@@ -5,6 +5,14 @@
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.account.api.feignClient.AppUserClient;
import com.ruoyi.account.api.model.TAppUser;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.constant.MsgConstants;
import com.ruoyi.common.core.utils.HttpUtils;
import com.ruoyi.common.core.utils.MsgUtil;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.system.api.domain.SysRole;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
@@ -25,6 +33,7 @@
import com.ruoyi.system.api.model.LoginUser;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
 * token 控制
@@ -42,7 +51,7 @@
    private SysLoginService sysLoginService;
    @Resource
    private SysUserClient userClient;
    
    
    
@@ -115,4 +124,5 @@
        sysLoginService.register(registerBody.getUsername(), registerBody.getPassword(), request);
        return R.ok();
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java
@@ -127,7 +127,10 @@
     */
    public static final String DATE_FORMATTER_TIME = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMATTER_DATE = "yyyy-MM-dd";
    /**
     * 后缀
     */
    public static final String APPLET = "_applet";
    /**
     * 定时任务违规的字符
     */
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/MsgConstants.java
New file
@@ -0,0 +1,35 @@
package com.ruoyi.common.core.constant;
/**
 * 短信常量
 *
 * @author ruoyi
 */
public class MsgConstants
{
    /** 短信发送地址 */
    public static final String SEND_URL = "http://112.35.1.155:1992/sms/tmpsubmit";
    /** 更换手机号短信验证码 TEMPLATE_ID */
    public static final String CODE_TEMPLATE_ID = "5bf3949463e54c03a25c6fce3ad48139";
    /** 停车占位提醒 TEMPLATE_ID */
    public static final String STOP_TEMPLATE_ID = "4940ce98a3f94f67aa9f5cd2d4e05cbd";
    /** 充电结束 TEMPLATE_ID */
    public static final String CHARGE_TEMPLATE_ID = "47b2eb376cfa436faae041a6f2f22688";
    /** 桩故障(自动/手动) TEMPLATE_ID */
    public static final String FAULT_TEMPLATE_ID = "37956469a14a47e484a747a1e7e462de";
    /** 更换手机号短信验证码 AP_ID */
    public static final String CODE_AP_ID = "GH123";
    /** 停车占位提醒 AP_ID */
    public static final String STOP_AP_ID = "TC123";
    /** 充电结束 AP_ID */
    public static final String CHARGE_AP_ID = "CD123";
    /** 桩故障(自动/手动) AP_ID */
    public static final String FAULT_AP_ID = "GZ123";
}
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/HttpUtils.java
New file
@@ -0,0 +1,311 @@
package com.ruoyi.common.core.utils;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
/**
 * 通用http发送方法
 *
 * @author ruoyi
 */
public class HttpUtils
{
    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url 发送请求的 URL
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url)
    {
        return sendGet(url, StringUtils.EMPTY);
    }
    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url 发送请求的 URL
     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param)
    {
        return sendGet(url, param, Constants.UTF8);
    }
    /**
     * 向指定 URL 发送GET方法的请求
     *
     * @param url 发送请求的 URL
     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @param contentType 编码类型
     * @return 所代表远程资源的响应结果
     */
    public static String sendGet(String url, String param, String contentType)
    {
        StringBuilder result = new StringBuilder();
        BufferedReader in = null;
        try
        {
            String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
            log.info("sendGet - {}", urlNameString);
            URL realUrl = new URL(urlNameString);
            URLConnection connection = realUrl.openConnection();
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.connect();
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
            String line;
            while ((line = in.readLine()) != null)
            {
                result.append(line);
            }
            log.info("recv - {}", result);
        }
        catch (ConnectException e)
        {
            log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
        }
        catch (IOException e)
        {
            log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
        }
        catch (Exception e)
        {
            log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
        }
        finally
        {
            try
            {
                if (in != null)
                {
                    in.close();
                }
            }
            catch (Exception ex)
            {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }
    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url 发送请求的 URL
     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param)
    {
        PrintWriter out = null;
        BufferedReader in = null;
        StringBuilder result = new StringBuilder();
        try
        {
            log.info("sendPost - {}", url);
            URL realUrl = new URL(url);
            URLConnection conn = realUrl.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("contentType", "utf-8");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            out = new PrintWriter(conn.getOutputStream());
            out.print(param);
            out.flush();
            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            String line;
            while ((line = in.readLine()) != null)
            {
                result.append(line);
            }
            log.info("recv - {}", result);
        }
        catch (ConnectException e)
        {
            log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        }
        catch (IOException e)
        {
            log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
        }
        catch (Exception e)
        {
            log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
        }
        finally
        {
            try
            {
                if (out != null)
                {
                    out.close();
                }
                if (in != null)
                {
                    in.close();
                }
            }
            catch (IOException ex)
            {
                log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
            }
        }
        return result.toString();
    }
    public static String sendSSLPost(String url, String param)
    {
        StringBuilder result = new StringBuilder();
        String urlNameString = url + "?" + param;
        try
        {
            log.info("sendSSLPost - {}", urlNameString);
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
            URL console = new URL(urlNameString);
            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Accept-Charset", "utf-8");
            conn.setRequestProperty("contentType", "utf-8");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setSSLSocketFactory(sc.getSocketFactory());
            conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
            conn.connect();
            InputStream is = conn.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String ret = "";
            while ((ret = br.readLine()) != null)
            {
                if (ret != null && !"".equals(ret.trim()))
                {
                    result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
                }
            }
            log.info("recv - {}", result);
            conn.disconnect();
            br.close();
        }
        catch (ConnectException e)
        {
            log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
        }
        catch (SocketTimeoutException e)
        {
            log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
        }
        catch (IOException e)
        {
            log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
        }
        catch (Exception e)
        {
            log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
        }
        return result.toString();
    }
    public static String post(String strURL, String params) {
        String result = "";
        BufferedReader reader = null;
        try {
            URL url = new URL(strURL);// 创建连接
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestMethod("POST"); // 设置请求方式
            connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式
            connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式
            connection.connect();
            if (params != null && !StringUtils.isEmpty(params)) {
                byte[] writebytes = params.getBytes();
                // 设置文件长度
                //   connection.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
                OutputStream outwritestream = connection.getOutputStream();
                outwritestream.write(params.getBytes());
                outwritestream.flush();
                outwritestream.close();
                // Log.d("hlhupload", "doJsonPost: conn"+connection.getResponseCode());
            }
            if (connection.getResponseCode() == 200) {
                log.info("<<<<<<<<<<<<<请求响应:{}", connection.getResponseMessage());
                reader = new BufferedReader(
                        new InputStreamReader(connection.getInputStream()));
                result = reader.readLine();
                log.info("<<<<<<<<<<<<<请求响应:{}", result);
            } else {
                throw new ServiceException(connection.getResponseMessage());
            }
        } catch (Exception e) {
            throw new ServiceException("http的post请求异常!" + e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
    private static class TrustAnyTrustManager implements X509TrustManager
    {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
        {
        }
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)
        {
        }
        @Override
        public X509Certificate[] getAcceptedIssuers()
        {
            return new X509Certificate[] {};
        }
    }
    private static class TrustAnyHostnameVerifier implements HostnameVerifier
    {
        @Override
        public boolean verify(String hostname, SSLSession session)
        {
            return true;
        }
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MD5Util.java
New file
@@ -0,0 +1,131 @@
package com.ruoyi.common.core.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Util {
 /**
     * 给指定字符串按照md5算法去加密
     *
     * @param psd 需要加密的密码   加盐处理
     *
     * @return md5后的字符串
     */
    public static String encoder(String psd) {
        try {
            //加盐处理
            psd = psd + "mobilesafe";
            //1,指定加密算法类型
            MessageDigest digest = MessageDigest.getInstance("MD5");
            //2,将需要加密的字符串中转换成byte类型的数组,然后进行随机哈希过程
            byte[] bs = digest.digest(psd.getBytes());
//          System.out.println(bs.length);
            //3,循环遍历bs,然后让其生成32位字符串,固定写法
            //4,拼接字符串过程
            StringBuffer stringBuffer = new StringBuffer();
            for (byte b : bs) {
                int i = b & 0xff;
                //int类型的i需要转换成16机制字符
                String hexString = Integer.toHexString(i);
//              System.out.println(hexString);
                if (hexString.length() < 2) {
                    hexString = "0" + hexString;
                }
                stringBuffer.append(hexString);
            }
            //5,打印测试
            System.out.println(stringBuffer.toString());
            return stringBuffer.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }
    /**
     * MD5加密字符串
     *
     * @param str
     * @return
     */
    public static String getMD5(String str) {
        if (StringUtils.isNotEmpty(str)) {
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                md.update(str.getBytes());
                byte b[] = md.digest();
                int i;
                StringBuffer buf = new StringBuffer("");
                for (int offset = 0; offset < b.length; offset++) {
                    i = b[offset];
                    if (i < 0)
                        i += 256;
                    if (i < 16)
                        buf.append("0");
                    buf.append(Integer.toHexString(i));
                }
                //32位加密(小写)
            return buf.toString();
            //32位加密(大写)
            //return buf.toString().toUpperCase();
            // 16位的加密(小写)
            //return buf.toString().substring(8, 24);
            // 16位的加密(大写)
            //return buf.toString().substring(8, 24).toUpperCase();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        return "";
    }
    /**
     * 获取32位大写
     *
     * @param str
     * @return
     */
    public static String getMD5_32_upper(String str) {
        if (StringUtils.isNotEmpty(str))
            return getMD5(str).toUpperCase();
        return "";
    }
    /**
     * 获取32位小写
     *
     * @param str
     * @return
     */
    public static String getMD5_32_lower(String str) {
        if (StringUtils.isNotEmpty(str))
            return getMD5(str).toLowerCase();
        return "";
    }
    /**
     * 获取16位大写
     *
     * @param str
     * @return
     */
    public static String getMD5_16_upper(String str) {
        if (StringUtils.isNotEmpty(str))
            return getMD5(str).substring(8, 24).toUpperCase();
        return "";
    }
    /**
     * 获取16位小写
     *
     * @param str
     * @return
     */
    public static String getMD5_16_lower(String str) {
        if (StringUtils.isNotEmpty(str))
            return getMD5(str).substring(8, 24).toLowerCase();
        return "";
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MsgUtil.java
New file
@@ -0,0 +1,163 @@
package com.ruoyi.common.core.utils;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.core.constant.MsgConstants;
import com.ruoyi.common.core.utils.req.SubmitTempletReq;
import org.apache.commons.codec.binary.Base64;
import java.util.concurrent.ThreadLocalRandom;
public class MsgUtil {
    public final static String ecName= "四川明星新能源科技有限公司";
    public final static String secretKey= "MX_xny2023?9";
    public final static String sign= "1PUAVuY2b";
    /**
     * 更换手机号:【签名】验证码:XXX,用于更换手机号。请勿转发。
     * @param phone 手机号
     * @param code 验证码
     * @return
     */
    public static String codeMsg(String phone,String code){
        SubmitTempletReq submitReq = new SubmitTempletReq();
        String[] paramss = {code};
        submitReq.setApId(MsgConstants.CODE_AP_ID);
        submitReq.setEcName(ecName);
        submitReq.setSecretKey(secretKey);
        submitReq.setParams(JSON.toJSONString(paramss));
        submitReq.setMobiles(phone);
        submitReq.setAddSerial("");
        submitReq.setSign(sign);
        submitReq.setTemplateId(MsgConstants.CODE_TEMPLATE_ID);
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(submitReq.getEcName());
        stringBuffer.append(submitReq.getApId());
        stringBuffer.append(submitReq.getSecretKey());
        stringBuffer.append(submitReq.getTemplateId());
        stringBuffer.append(submitReq.getMobiles());
        stringBuffer.append(submitReq.getParams());
        stringBuffer.append(submitReq.getSign());
        stringBuffer.append(submitReq.getAddSerial());
        submitReq.setMac(MD5Util.getMD5(stringBuffer.toString()));
        String reqText = JSON.toJSONString(submitReq);
        //加密
        String encode = Base64.encodeBase64String(reqText.getBytes());
        System.err.println(encode);
        return encode;
    }
    /**
     * 停车占位提醒:车辆已在3小时前完成充电,请及时取车,避免长时间占用充电资源。
     * @param phone 手机号
     * @return
     */
    public static String stopMsg(String phone){
        SubmitTempletReq submitReq = new SubmitTempletReq();
        submitReq.setTemplateId(MsgConstants.STOP_TEMPLATE_ID);
        submitReq.setApId(MsgConstants.STOP_AP_ID);
        submitReq.setEcName(ecName);
        submitReq.setSecretKey(secretKey);
        submitReq.setMobiles(phone);
        submitReq.setAddSerial("");
        submitReq.setSign(sign);
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(submitReq.getEcName());
        stringBuffer.append(submitReq.getApId());
        stringBuffer.append(submitReq.getSecretKey());
        stringBuffer.append(submitReq.getTemplateId());
        stringBuffer.append(submitReq.getMobiles());
        stringBuffer.append(submitReq.getParams());
        stringBuffer.append(submitReq.getSign());
        stringBuffer.append(submitReq.getAddSerial());
        submitReq.setMac(MD5Util.getMD5(stringBuffer.toString()));
        String reqText = JSON.toJSONString(submitReq);
        //加密
        String encode = Base64.encodeBase64String(reqText.getBytes());
        System.err.println(encode);
        return encode;
    }
    /**
     * 充电结束:车辆充电结束,请及时取车。
     * @param phone 手机号
     * @return
     */
    public static String chargeStopMsg(String phone){
        SubmitTempletReq submitReq = new SubmitTempletReq();
        submitReq.setTemplateId(MsgConstants.CHARGE_TEMPLATE_ID);
        submitReq.setApId(MsgConstants.CHARGE_AP_ID);
        submitReq.setEcName(ecName);
        submitReq.setSecretKey(secretKey);
        submitReq.setMobiles(phone);
        submitReq.setAddSerial("");
        submitReq.setSign(sign);
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(submitReq.getEcName());
        stringBuffer.append(submitReq.getApId());
        stringBuffer.append(submitReq.getSecretKey());
        stringBuffer.append(submitReq.getTemplateId());
        stringBuffer.append(submitReq.getMobiles());
        stringBuffer.append(submitReq.getParams());
        stringBuffer.append(submitReq.getSign());
        stringBuffer.append(submitReq.getAddSerial());
        submitReq.setMac(MD5Util.getMD5(stringBuffer.toString()));
        String reqText = JSON.toJSONString(submitReq);
        //加密
        String encode = Base64.encodeBase64String(reqText.getBytes());
        System.err.println(encode);
        return encode;
    }
    /**  phone  单词可拼接5000个号码
     * 桩故障(自动/手动):检测到【电站1】【编号】号桩设备离线,请及时查看处理!
     * @param phone 手机号
     * @param site 站点名称
     * @param chargeGun 桩编号
     * @return
     */
    public static String faultMsg(String phone,String site,String chargeGun){
        SubmitTempletReq submitReq = new SubmitTempletReq();
        if(site.length()<=10){
            String[] paramss = {site,chargeGun};
            submitReq.setParams(JSON.toJSONString(paramss));
        }else{
            String work1 = site.substring(0,10);
            String[] paramss = {work1,chargeGun};
            submitReq.setParams(JSON.toJSONString(paramss));
        }
        submitReq.setTemplateId(MsgConstants.FAULT_TEMPLATE_ID);
        submitReq.setApId(MsgConstants.FAULT_AP_ID);
        submitReq.setEcName(ecName);
        submitReq.setSecretKey(secretKey);
        submitReq.setMobiles(phone);
        submitReq.setAddSerial("");
        submitReq.setSign(sign);
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(submitReq.getEcName());
        stringBuffer.append(submitReq.getApId());
        stringBuffer.append(submitReq.getSecretKey());
        stringBuffer.append(submitReq.getTemplateId());
        stringBuffer.append(submitReq.getMobiles());
        stringBuffer.append(submitReq.getParams());
        stringBuffer.append(submitReq.getSign());
        stringBuffer.append(submitReq.getAddSerial());
        submitReq.setMac(MD5Util.getMD5(stringBuffer.toString()));
        String reqText = JSON.toJSONString(submitReq);
        //加密
        String encode = Base64.encodeBase64String(reqText.getBytes());
        System.err.println(encode);
        return encode;
    }
    /**
     * 生成验证码
     * @return
     */
    public static String createCode(){
        return String.valueOf(ThreadLocalRandom.current().nextInt(100000, 999999));
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/req/SubmitTempletReq.java
New file
@@ -0,0 +1,47 @@
package com.ruoyi.common.core.utils.req;
import lombok.Data;
import java.io.Serializable;
@Data
public class SubmitTempletReq implements Serializable {
    /**
     * 企业名称
     */
    private String ecName;
    /**
     * 接口账号用户名
     */
    private String apId;
    /**
     * 密码
     */
    private String secretKey;
    /**
     * 模板ID。在云MAS平台创建模板,路径:『短信』→『模板短信』→『模板管理』,创建后提交审核,审核通过将获得模板ID。
     */
    private String templateId;
    /**
     * 收信手机号码。英文逗号分隔,每批次限5000个号码,例:“13800138000,13800138001,13800138002”。
     */
    private String mobiles;
    /**
     * 模板变量。格式:[“param1”,“param2”],无变量模板填[""]
     */
    private String params;
    /**
     * 签名
     */
    private String sign;
    /**
     * 扩展码。依据开户时申请的服务代码匹配类型而定,如为精确匹配,此项填写空字符串("");如为模糊匹配,此项可填写空字符串或自定义的扩展码,注:服务代码加扩展码总长度不能超过20位。
     */
    private String addSerial;
    /**
     * 参数校验序列,生成方法:将ecName、apId、secretKey、templateId、mobiles、params、sign、addSerial按序拼接(无间隔符),通过MD5(32位小写)计算出的值。
     */
    private String mac;
}
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/domain/BaseDelete.java
New file
@@ -0,0 +1,14 @@
package com.ruoyi.common.core.web.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
public class BaseDelete {
    @ApiModelProperty(value = "id集合")
    private List<Integer> ids;
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/RuoYiGatewayApplication.java
@@ -6,24 +6,22 @@
/**
 * 网关启动程序
 *
 *
 * @author ruoyi
 */
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class RuoYiGatewayApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(RuoYiGatewayApplication.class, args);
        System.out.println("(♥◠‿◠)ノ゙  若依网关启动成功   ლ(´ڡ`ლ)゙  \n" +
                " .-------.       ____     __        \n" +
                " |  _ _   \\      \\   \\   /  /    \n" +
                " | ( ' )  |       \\  _. /  '       \n" +
                " |(_ o _) /        _( )_ .'         \n" +
                " | (_,_).' __  ___(_ o _)'          \n" +
                " |  |\\ \\  |  ||   |(_,_)'         \n" +
                " |  | \\ `'   /|   `-'  /           \n" +
                " |  |  \\    /  \\      /           \n" +
                " ''-'   `'-'    `-..-'              ");
    }
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class RuoYiGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(RuoYiGatewayApplication.class, args);
        System.out.println("(♥◠‿◠)ノ゙  若依网关启动成功   ლ(´ڡ`ლ)゙  \n" +
                " .-------.       ____     __        \n" +
                " |  _ _   \\      \\   \\   /  /    \n" +
                " | ( ' )  |       \\  _. /  '       \n" +
                " |(_ o _) /        _( )_ .'         \n" +
                " | (_,_).' __  ___(_ o _)'          \n" +
                " |  |\\ \\  |  ||   |(_,_)'         \n" +
                " |  | \\ `'   /|   `-'  /           \n" +
                " |  |  \\    /  \\      /           \n" +
                " ''-'   `'-'    `-..-'              ");
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/CaptchaConfig.java
@@ -1,83 +1,82 @@
package com.ruoyi.gateway.config;
import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import static com.google.code.kaptcha.Constants.*;
/**
 * 验证码配置
 *
 *
 * @author ruoyi
 */
@Configuration
public class CaptchaConfig
{
    @Bean(name = "captchaProducer")
    public DefaultKaptcha getKaptchaBean()
    {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有边框 默认为true 我们可以自己设置yes,no
        properties.setProperty(KAPTCHA_BORDER, "yes");
        // 验证码文本字符颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
        // 验证码图片宽度 默认为200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // 验证码图片高度 默认为50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // 验证码文本字符大小 默认为40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
        // KAPTCHA_SESSION_KEY
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
        // 验证码文本字符长度 默认为5
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
    @Bean(name = "captchaProducerMath")
    public DefaultKaptcha getKaptchaBeanMath()
    {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有边框 默认为true 我们可以自己设置yes,no
        properties.setProperty(KAPTCHA_BORDER, "yes");
        // 边框颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
        // 验证码文本字符颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
        // 验证码图片宽度 默认为200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // 验证码图片高度 默认为50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // 验证码文本字符大小 默认为40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
        // KAPTCHA_SESSION_KEY
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
        // 验证码文本生成器
        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.gateway.config.KaptchaTextCreator");
        // 验证码文本字符间距 默认为2
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
        // 验证码文本字符长度 默认为5
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        // 验证码噪点颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
        // 干扰实现类
        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
public class CaptchaConfig {
    @Bean(name = "captchaProducer")
    public DefaultKaptcha getKaptchaBean() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有边框 默认为true 我们可以自己设置yes,no
        properties.setProperty(KAPTCHA_BORDER, "yes");
        // 验证码文本字符颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
        // 验证码图片宽度 默认为200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // 验证码图片高度 默认为50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // 验证码文本字符大小 默认为40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
        // KAPTCHA_SESSION_KEY
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
        // 验证码文本字符长度 默认为5
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
    @Bean(name = "captchaProducerMath")
    public DefaultKaptcha getKaptchaBeanMath() {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // 是否有边框 默认为true 我们可以自己设置yes,no
        properties.setProperty(KAPTCHA_BORDER, "yes");
        // 边框颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
        // 验证码文本字符颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
        // 验证码图片宽度 默认为200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // 验证码图片高度 默认为50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // 验证码文本字符大小 默认为40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
        // KAPTCHA_SESSION_KEY
        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
        // 验证码文本生成器
        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.gateway.config.KaptchaTextCreator");
        // 验证码文本字符间距 默认为2
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
        // 验证码文本字符长度 默认为5
        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
        // 验证码噪点颜色 默认为Color.BLACK
        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
        // 干扰实现类
        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java
@@ -8,16 +8,14 @@
/**
 * 网关限流配置
 *
 *
 * @author ruoyi
 */
@Configuration
public class GatewayConfig
{
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelFallbackHandler sentinelGatewayExceptionHandler()
    {
        return new SentinelFallbackHandler();
    }
public class GatewayConfig {
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelFallbackHandler sentinelGatewayExceptionHandler() {
        return new SentinelFallbackHandler();
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/KaptchaTextCreator.java
@@ -1,75 +1,61 @@
package com.ruoyi.gateway.config;
import java.util.Random;
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
/**
 * 验证码文本生成器
 *
 *
 * @author ruoyi
 */
public class KaptchaTextCreator extends DefaultTextCreator
{
    private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
    @Override
    public String getText()
    {
        Integer result = 0;
        Random random = new Random();
        int x = random.nextInt(10);
        int y = random.nextInt(10);
        StringBuilder suChinese = new StringBuilder();
        int randomoperands = random.nextInt(3);
        if (randomoperands == 0)
        {
            result = x * y;
            suChinese.append(CNUMBERS[x]);
            suChinese.append("*");
            suChinese.append(CNUMBERS[y]);
        }
        else if (randomoperands == 1)
        {
            if ((x != 0) && y % x == 0)
            {
                result = y / x;
                suChinese.append(CNUMBERS[y]);
                suChinese.append("/");
                suChinese.append(CNUMBERS[x]);
            }
            else
            {
                result = x + y;
                suChinese.append(CNUMBERS[x]);
                suChinese.append("+");
                suChinese.append(CNUMBERS[y]);
            }
        }
        else if (randomoperands == 2)
        {
            if (x >= y)
            {
                result = x - y;
                suChinese.append(CNUMBERS[x]);
                suChinese.append("-");
                suChinese.append(CNUMBERS[y]);
            }
            else
            {
                result = y - x;
                suChinese.append(CNUMBERS[y]);
                suChinese.append("-");
                suChinese.append(CNUMBERS[x]);
            }
        }
        else
        {
            result = x + y;
            suChinese.append(CNUMBERS[x]);
            suChinese.append("+");
            suChinese.append(CNUMBERS[y]);
        }
        suChinese.append("=?@" + result);
        return suChinese.toString();
    }
public class KaptchaTextCreator extends DefaultTextCreator {
    private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
    @Override
    public String getText() {
        Integer result = 0;
        Random random = new Random();
        int x = random.nextInt(10);
        int y = random.nextInt(10);
        StringBuilder suChinese = new StringBuilder();
        int randomoperands = random.nextInt(3);
        if (randomoperands == 0) {
            result = x * y;
            suChinese.append(CNUMBERS[x]);
            suChinese.append("*");
            suChinese.append(CNUMBERS[y]);
        } else if (randomoperands == 1) {
            if ((x != 0) && y % x == 0) {
                result = y / x;
                suChinese.append(CNUMBERS[y]);
                suChinese.append("/");
                suChinese.append(CNUMBERS[x]);
            } else {
                result = x + y;
                suChinese.append(CNUMBERS[x]);
                suChinese.append("+");
                suChinese.append(CNUMBERS[y]);
            }
        } else if (randomoperands == 2) {
            if (x >= y) {
                result = x - y;
                suChinese.append(CNUMBERS[x]);
                suChinese.append("-");
                suChinese.append(CNUMBERS[y]);
            } else {
                result = y - x;
                suChinese.append(CNUMBERS[y]);
                suChinese.append("-");
                suChinese.append(CNUMBERS[x]);
            }
        } else {
            result = x + y;
            suChinese.append(CNUMBERS[x]);
            suChinese.append("+");
            suChinese.append(CNUMBERS[y]);
        }
        suChinese.append("=?@" + result);
        return suChinese.toString();
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/RouterFunctionConfiguration.java
@@ -21,59 +21,54 @@
/**
 * 路由配置信息
 *
 *
 * @author ruoyi
 */
@Configuration
public class RouterFunctionConfiguration
{
    /**
     * 这里为支持的请求头,如果有自定义的header字段请自己添加
     */
    private static final String ALLOWED_HEADERS = "X-Requested-With, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, username, client, request-origion, sign, nonce_str";
    private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";
    private static final String ALLOWED_ORIGIN = "*";
    private static final String ALLOWED_EXPOSE = "*";
    private static final String MAX_AGE = "18000L";
    @Autowired
    private ValidateCodeHandler validateCodeHandler;
    @SuppressWarnings("rawtypes")
    @Bean
    public RouterFunction routerFunction()
    {
        return RouterFunctions.route(
                RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                validateCodeHandler);
    }
    /**
     * 跨域配置
     */
    @Bean
    public WebFilter corsFilter()
    {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request))
            {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
                headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
                headers.add("Access-Control-Max-Age", MAX_AGE);
                headers.add("Access-Control-Allow-Credentials", "true");
                if (request.getMethod() == HttpMethod.OPTIONS)
                {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
public class RouterFunctionConfiguration {
    /**
     * 这里为支持的请求头,如果有自定义的header字段请自己添加
     */
    private static final String ALLOWED_HEADERS = "X-Requested-With, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, username, client, request-origion, sign, nonce_str, timestamp";
    private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";
    private static final String ALLOWED_ORIGIN = "*";
    private static final String ALLOWED_EXPOSE = "*";
    private static final String MAX_AGE = "18000L";
    @Autowired
    private ValidateCodeHandler validateCodeHandler;
    @SuppressWarnings("rawtypes")
    @Bean
    public RouterFunction routerFunction() {
        return RouterFunctions.route(
                RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                validateCodeHandler);
    }
    /**
     * 跨域配置
     */
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
                headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
                headers.add("Access-Control-Max-Age", MAX_AGE);
                headers.add("Access-Control-Allow-Credentials", "true");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/SwaggerProvider.java
@@ -2,6 +2,7 @@
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
@@ -15,65 +16,61 @@
/**
 * 聚合系统接口
 *
 *
 * @author ruoyi
 */
@Component
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer
{
    /**
     * Swagger2默认的url后缀
     */
    public static final String SWAGGER2URL = "/v2/api-docs";
    /**
     * 网关路由
     */
    @Lazy
    @Autowired
    private RouteLocator routeLocator;
    @Autowired
    private GatewayProperties gatewayProperties;
    /**
     * 聚合其他服务接口
     *
     * @return
     */
    @Override
    public List<SwaggerResource> get()
    {
        List<SwaggerResource> resourceList = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        // 获取网关中配置的route
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        gatewayProperties.getRoutes().stream()
                .filter(routeDefinition -> routes
                        .contains(routeDefinition.getId()))
                .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                        .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
                        .filter(predicateDefinition -> !"ruoyi-auth".equalsIgnoreCase(routeDefinition.getId()))
                        .forEach(predicateDefinition -> resourceList
                                .add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
                                        .get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL)))));
        return resourceList;
    }
    private SwaggerResource swaggerResource(String name, String location)
    {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry)
    {
        /** swagger-ui 地址 */
        registry.addResourceHandler("/swagger-ui/**","*/doc.html")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
    }
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer {
    /**
     * Swagger2默认的url后缀
     */
    public static final String SWAGGER2URL = "/v2/api-docs";
    /**
     * 网关路由
     */
    @Lazy
    @Autowired
    private RouteLocator routeLocator;
    @Autowired
    private GatewayProperties gatewayProperties;
    /**
     * 聚合其他服务接口
     *
     * @return
     */
    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resourceList = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        // 获取网关中配置的route
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        gatewayProperties.getRoutes().stream()
                .filter(routeDefinition -> routes
                        .contains(routeDefinition.getId()))
                .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                        .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
                        .filter(predicateDefinition -> !"ruoyi-auth".equalsIgnoreCase(routeDefinition.getId()))
                        .forEach(predicateDefinition -> resourceList
                                .add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
                                        .get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL)))));
        return resourceList;
    }
    private SwaggerResource swaggerResource(String name, String location) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("2.0");
        return swaggerResource;
    }
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        /** swagger-ui 地址 */
        registry.addResourceHandler("/swagger-ui/**", "*/doc.html")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/CaptchaProperties.java
@@ -6,41 +6,36 @@
/**
 * 验证码配置
 *
 *
 * @author ruoyi
 */
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "security.captcha")
public class CaptchaProperties
{
    /**
     * 验证码开关
     */
    private Boolean enabled;
    /**
     * 验证码类型(math 数组计算 char 字符)
     */
    private String type;
    public Boolean getEnabled()
    {
        return enabled;
    }
    public void setEnabled(Boolean enabled)
    {
        this.enabled = enabled;
    }
    public String getType()
    {
        return type;
    }
    public void setType(String type)
    {
        this.type = type;
    }
public class CaptchaProperties {
    /**
     * 验证码开关
     */
    private Boolean enabled;
    /**
     * 验证码类型(math 数组计算 char 字符)
     */
    private String type;
    public Boolean getEnabled() {
        return enabled;
    }
    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/IgnoreWhiteProperties.java
@@ -2,32 +2,30 @@
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
/**
 * 放行白名单配置
 *
 *
 * @author ruoyi
 */
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "security.ignore")
public class IgnoreWhiteProperties
{
    /**
     * 放行白名单配置,网关不校验此处的白名单
     */
    private List<String> whites = new ArrayList<>();
    public List<String> getWhites()
    {
        return whites;
    }
    public void setWhites(List<String> whites)
    {
        this.whites = whites;
    }
public class IgnoreWhiteProperties {
    /**
     * 放行白名单配置,网关不校验此处的白名单
     */
    private List<String> whites = new ArrayList<>();
    public List<String> getWhites() {
        return whites;
    }
    public void setWhites(List<String> whites) {
        this.whites = whites;
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/config/properties/XssProperties.java
@@ -2,47 +2,43 @@
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
/**
 * XSS跨站脚本配置
 *
 *
 * @author ruoyi
 */
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "security.xss")
public class XssProperties
{
    /**
     * Xss开关
     */
    private Boolean enabled;
    /**
     * 排除路径
     */
    private List<String> excludeUrls = new ArrayList<>();
    public Boolean getEnabled()
    {
        return enabled;
    }
    public void setEnabled(Boolean enabled)
    {
        this.enabled = enabled;
    }
    public List<String> getExcludeUrls()
    {
        return excludeUrls;
    }
    public void setExcludeUrls(List<String> excludeUrls)
    {
        this.excludeUrls = excludeUrls;
    }
public class XssProperties {
    /**
     * Xss开关
     */
    private Boolean enabled;
    /**
     * 排除路径
     */
    private List<String> excludeUrls = new ArrayList<>();
    public Boolean getEnabled() {
        return enabled;
    }
    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }
    public List<String> getExcludeUrls() {
        return excludeUrls;
    }
    public void setExcludeUrls(List<String> excludeUrls) {
        this.excludeUrls = excludeUrls;
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/AuthFilter.java
@@ -36,102 +36,106 @@
/**
 * 网关鉴权
 *
 *
 * @author ruoyi
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
    // 排除过滤的 uri 地址,nacos自行添加
    @Autowired
    private IgnoreWhiteProperties ignoreWhite;
    @Autowired
    private RedisService redisService;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();
        String url = request.getURI().getPath();
        // 跳过不需要验证的路径
        if (StringUtils.matches(url, ignoreWhite.getWhites())) {
            return chain.filter(exchange);
        }
        String token = getToken(request);
        if (StringUtils.isEmpty(token)) {
            return unauthorizedResponse(exchange, "令牌不能为空");
        }
        Claims claims = JwtUtils.parseToken(token);
        if (claims == null) {
            return unauthorizedResponse(exchange, "令牌已过期或验证不正确!");
        }
        String userkey = JwtUtils.getUserKey(claims);
        boolean islogin = redisService.hasKey(getTokenKey(userkey));
        if (!islogin) {
            return unauthorizedResponse(exchange, "登录状态已过期");
        }
        String userid = JwtUtils.getUserId(claims);
        String username = JwtUtils.getUserName(claims);
        if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) {
            return unauthorizedResponse(exchange, "令牌验证失败");
        }
        // 设置用户信息到请求
        addHeader(mutate, SecurityConstants.USER_KEY, userkey);
        addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid);
        addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username);
        // 内部请求来源参数清除
        removeHeader(mutate, SecurityConstants.FROM_SOURCE);
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }
    private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) {
        if (value == null) {
            return;
        }
        String valueStr = value.toString();
        String valueEncode = ServletUtils.urlEncode(valueStr);
        mutate.header(name, valueEncode);
    }
    private void removeHeader(ServerHttpRequest.Builder mutate, String name) {
        mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
    }
    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
        log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
    }
    /**
     * 获取缓存key
     */
    private String getTokenKey(String token)
    {
        return CacheConstants.LOGIN_TOKEN_KEY + token;
    }
    /**
     * 获取请求token
     */
    private String getToken(ServerHttpRequest request) {
        String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
        // 如果前端设置了令牌前缀,则裁剪掉前缀
        if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
        {
            token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
        }
        return token;
    }
    @Override
    public int getOrder()
    {
        return -300;
    }
    private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
    // 排除过滤的 uri 地址,nacos自行添加
    @Autowired
    private IgnoreWhiteProperties ignoreWhite;
    @Autowired
    private RedisService redisService;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();
        String url = request.getURI().getPath();
        // 跳过不需要验证的路径
        if (StringUtils.matches(url, ignoreWhite.getWhites())) {
            return chain.filter(exchange);
        }
        String token = getToken(request);
        if (StringUtils.isEmpty(token)) {
            return unauthorizedResponse(exchange, "令牌不能为空");
        }
        Claims claims = JwtUtils.parseToken(token);
        if (claims == null) {
            return unauthorizedResponse(exchange, "令牌已过期或验证不正确!");
        }
        String userkey = JwtUtils.getUserKey(claims);
        boolean islogin = redisService.hasKey(getTokenKey(userkey));
        if (!islogin) {
            return unauthorizedResponse(exchange, "登录状态已过期");
        }
        String userid = JwtUtils.getUserId(claims);
        String username = JwtUtils.getUserName(claims);
        if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) {
            return unauthorizedResponse(exchange, "令牌验证失败");
        }
        // 设置用户信息到请求
        addHeader(mutate, SecurityConstants.USER_KEY, userkey);
        addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid);
        addHeader(mutate, SecurityConstants.DETAILS_USERNAME, username);
        // 内部请求来源参数清除
        removeHeader(mutate, SecurityConstants.FROM_SOURCE);
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }
    private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) {
        if (value == null) {
            return;
        }
        String valueStr = value.toString();
        String valueEncode = ServletUtils.urlEncode(valueStr);
        mutate.header(name, valueEncode);
    }
    private void removeHeader(ServerHttpRequest.Builder mutate, String name) {
        mutate.headers(httpHeaders -> httpHeaders.remove(name)).build();
    }
    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
        log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
    }
    /**
     * 获取缓存key
     */
    private String getTokenKey(String token) {
        return CacheConstants.LOGIN_TOKEN_KEY + token;
    }
    /**
     * 获取请求token
     */
    private String getToken(ServerHttpRequest request) {
        String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
        // 如果前端设置了令牌前缀,则裁剪掉前缀
        if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) {
            token = token.replaceFirst(TokenConstants.PREFIX, StringUtils.EMPTY);
        }
        return token;
    }
    /**
     * 防抖处理
     */
    @Override
    public int getOrder() {
        return -300;
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java
@@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
@@ -10,56 +11,48 @@
/**
 * 黑名单过滤器
 *
 *
 * @author ruoyi
 */
@Component
public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUrlFilter.Config>
{
    @Override
    public GatewayFilter apply(Config config)
    {
        return (exchange, chain) -> {
            String url = exchange.getRequest().getURI().getPath();
            if (config.matchBlacklist(url))
            {
                return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问");
            }
            return chain.filter(exchange);
        };
    }
    public BlackListUrlFilter()
    {
        super(Config.class);
    }
    public static class Config
    {
        private List<String> blacklistUrl;
        private List<Pattern> blacklistUrlPattern = new ArrayList<>();
        public boolean matchBlacklist(String url)
        {
            return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find());
        }
        public List<String> getBlacklistUrl()
        {
            return blacklistUrl;
        }
        public void setBlacklistUrl(List<String> blacklistUrl)
        {
            this.blacklistUrl = blacklistUrl;
            this.blacklistUrlPattern.clear();
            this.blacklistUrl.forEach(url -> {
                this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE));
            });
        }
    }
public class BlackListUrlFilter extends AbstractGatewayFilterFactory<BlackListUrlFilter.Config> {
    public BlackListUrlFilter() {
        super(Config.class);
    }
    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            String url = exchange.getRequest().getURI().getPath();
            if (config.matchBlacklist(url)) {
                return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问");
            }
            return chain.filter(exchange);
        };
    }
    public static class Config {
        private List<String> blacklistUrl;
        private List<Pattern> blacklistUrlPattern = new ArrayList<>();
        public boolean matchBlacklist(String url) {
            return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find());
        }
        public List<String> getBlacklistUrl() {
            return blacklistUrl;
        }
        public void setBlacklistUrl(List<String> blacklistUrl) {
            this.blacklistUrl = blacklistUrl;
            this.blacklistUrlPattern.clear();
            this.blacklistUrl.forEach(url -> {
                this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE));
            });
        }
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/CacheRequestFilter.java
@@ -2,6 +2,7 @@
import java.util.Collections;
import java.util.List;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
@@ -14,74 +15,61 @@
/**
 * 获取body请求数据(解决流不能重复读取问题)
 *
 *
 * @author ruoyi
 */
@Component
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config>
{
    public CacheRequestFilter()
    {
        super(Config.class);
    }
    @Override
    public String name()
    {
        return "CacheRequestFilter";
    }
    @Override
    public GatewayFilter apply(Config config)
    {
        CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter();
        Integer order = config.getOrder();
        if (order == null)
        {
            return cacheRequestGatewayFilter;
        }
        return new OrderedGatewayFilter(cacheRequestGatewayFilter, order);
    }
    public static class CacheRequestGatewayFilter implements GatewayFilter
    {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
        {
            // GET DELETE 不过滤
            HttpMethod method = exchange.getRequest().getMethod();
            if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE)
            {
                return chain.filter(exchange);
            }
            return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> {
                if (serverHttpRequest == exchange.getRequest())
                {
                    return chain.filter(exchange);
                }
                return chain.filter(exchange.mutate().request(serverHttpRequest).build());
            });
        }
    }
    @Override
    public List<String> shortcutFieldOrder()
    {
        return Collections.singletonList("order");
    }
    static class Config
    {
        private Integer order;
        public Integer getOrder()
        {
            return order;
        }
        public void setOrder(Integer order)
        {
            this.order = order;
        }
    }
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config> {
    public CacheRequestFilter() {
        super(Config.class);
    }
    @Override
    public String name() {
        return "CacheRequestFilter";
    }
    @Override
    public GatewayFilter apply(Config config) {
        CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter();
        Integer order = config.getOrder();
        if (order == null) {
            return cacheRequestGatewayFilter;
        }
        return new OrderedGatewayFilter(cacheRequestGatewayFilter, order);
    }
    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("order");
    }
    public static class CacheRequestGatewayFilter implements GatewayFilter {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            // GET DELETE 不过滤
            HttpMethod method = exchange.getRequest().getMethod();
            if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE) {
                return chain.filter(exchange);
            }
            return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> {
                if (serverHttpRequest == exchange.getRequest()) {
                    return chain.filter(exchange);
                }
                return chain.filter(exchange.mutate().request(serverHttpRequest).build());
            });
        }
    }
    static class Config {
        private Integer order;
        public Integer getOrder() {
            return order;
        }
        public void setOrder(Integer order) {
            this.order = order;
        }
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/HMACSHA1.java
@@ -6,17 +6,15 @@
import javax.crypto.spec.SecretKeySpec;
public class HMACSHA1 {
    private static final String MAC_NAME = "HmacSHA1";
    private static final String ENCODING = "UTF-8";
    /**
     * 使用 HMAC-SHA1 签名方法对对encryptText进行签名
     *
     * @param encryptText
     *            被签名的字符串
     * @param encryptKey
     *            密钥
     *
     * @param encryptText 被签名的字符串
     * @param encryptKey  密钥
     * @return
     * @throws Exception
     */
@@ -28,7 +26,7 @@
        // 生成一个指定 Mac 算法 的 Mac 对象
        // 用给定密钥初始化 Mac 对象
        mac.init(secretKey);
        byte[] text = encryptText.getBytes(ENCODING);
        // 完成 Mac 操作
        return mac.doFinal(text);
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/RequestParamGlobalFilter.java
@@ -42,57 +42,53 @@
 */
@Component
public class RequestParamGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange);
        return chain.filter(exchange.mutate().request(httpRequestDecorator).build());
    }
    private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange) {
        ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
            @Override
            public Flux<DataBuffer> getBody() {
                Flux<DataBuffer> body = super.getBody();
                return body.buffer().map(dataBuffers -> {
                    DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                    DataBuffer join = dataBufferFactory.join(dataBuffers);
                    byte[] content = new byte[join.readableByteCount()];
                    join.read(content);
                    DataBufferUtils.release(join);
                    String bodyStr = new String(content, StandardCharsets.UTF_8);
                    // 转成字节
                    byte[] bytes = bodyStr.getBytes();
                    NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
                    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
                    buffer.write(bytes);
                    return buffer;
                });
            }
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                // 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
                httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                return httpHeaders;
            }
        };
        return serverHttpRequestDecorator;
    }
    @Override
    public int getOrder()
    {
        return HIGHEST_PRECEDENCE;
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange);
        return chain.filter(exchange.mutate().request(httpRequestDecorator).build());
    }
    private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange) {
        ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
            @Override
            public Flux<DataBuffer> getBody() {
                Flux<DataBuffer> body = super.getBody();
                return body.buffer().map(dataBuffers -> {
                    DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                    DataBuffer join = dataBufferFactory.join(dataBuffers);
                    byte[] content = new byte[join.readableByteCount()];
                    join.read(content);
                    DataBufferUtils.release(join);
                    String bodyStr = new String(content, StandardCharsets.UTF_8);
                    // 转成字节
                    byte[] bytes = bodyStr.getBytes();
                    NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
                    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
                    buffer.write(bytes);
                    return buffer;
                });
            }
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                // 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
                httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                return httpHeaders;
            }
        };
        return serverHttpRequestDecorator;
    }
    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/SignFilter.java
@@ -40,155 +40,149 @@
/**
 * 网关鉴权
 *
 *
 * @author ruoyi
 */
@Component
public class SignFilter implements GlobalFilter, Ordered {
    private static final Logger log = LoggerFactory.getLogger(SignFilter.class);
    // 排除过滤的 uri 地址,nacos自行添加
    @Autowired
    private IgnoreWhiteProperties ignoreWhite;
    @Autowired
    private RedisService redisService;
    @Value("${security.sign}")
    private boolean parameter_signature;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();
        HttpMethod method = request.getMethod();
        if(method != HttpMethod.POST){
            return chain.filter(exchange.mutate().request(mutate.build()).build());
        }
        String sign = request.getHeaders().getFirst(TokenConstants.SIGN);
        String nonce_str = request.getHeaders().getFirst(TokenConstants.NONCE_STR);
        if (parameter_signature && StringUtils.isEmpty(sign)) {
            return unauthorizedResponse(exchange, "签名不能为空!");
        }
        if (parameter_signature && StringUtils.isEmpty(nonce_str)) {
            return unauthorizedResponse(exchange, "签名不能为空!");
        }
        if(parameter_signature){
            return authSign(exchange, chain, sign, nonce_str);
        }
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }
    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
        log.error("[签名异常处理]请求路径:{}", exchange.getRequest().getPath());
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.BAD_REQUEST);
    }
    /**
     * 校验签名
     * @return
     */
    private Mono<Void> authSign(ServerWebExchange exchange, GatewayFilterChain chain, String sign, String nonce_str){
        return DataBufferUtils.join(exchange.getRequest().getBody())
                .flatMap(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes);
                    String bodyString = new String(bytes, StandardCharsets.UTF_8);
                    log.info("请求参数:{}", bodyString);
                    if(!authSign(JSON.parseObject(bodyString), sign, nonce_str)){
                        return unauthorizedResponse(exchange, "签名验证失败!");
                    }
                    DataBufferUtils.release(dataBuffer);
                    Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                        DataBuffer buffer = exchange.getResponse().bufferFactory()
                                .wrap(bytes);
                        return Mono.just(buffer);
                    });
                    ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
                        @Override
                        public Flux<DataBuffer> getBody() {
                            return cachedFlux;
                        }
                    };
                    return chain.filter(exchange.mutate().request(mutatedRequest)
                            .build());
        });
    }
    /**
     * 签名校验
     * @return
     */
    private boolean authSign(JSONObject jsonStr, String sign, String nonce_str) {
        System.err.println("请求签名:" + sign);
        String signUrlEncode = localSignUrl(jsonStr, nonce_str);
        signUrlEncode = signUrlEncode.replaceAll("& #40;", "\\(")
                .replaceAll("& #41;", "\\)");
        if(sign.equals(signUrlEncode)){
            return true;
        }
        System.err.println("签名值:" + signUrlEncode);
        return false;
    }
    /**
     * 组装签名路径
     * @param params
     * @return
     */
    public static String localSignUrl(JSONObject params, String key) {
        List<String> keySet = new ArrayList<>(params.keySet());
        // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
        Collections.sort(keySet, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        // 构造签名键值对的格式
        StringBuilder sb = new StringBuilder();
        for (String k : keySet) {
            String v = params.getString(k);
            if(StringUtils.isNotEmpty(v)){
                sb.append(k + "=" + v + "&");
            }
        }
        String signUrl = sb.substring(0, sb.length() - 1);
        System.err.println("签名串:" + signUrl);
        return signUrlEncode(signUrl, key);
    }
    /**
     * 签名字符串加密
     * @param signUrl
     * @param encryptKey
     * @return
     */
    public static String signUrlEncode(String signUrl, String encryptKey) {
        byte[] signByte = new byte[0];
        try {
            signByte = HMACSHA1.HmacSHA1Encrypt(signUrl, encryptKey);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        String localSign = Base64.encodeBase64String(signByte);
        return localSign;
    }
    @Override
    public int getOrder()
    {
        return -200;
    }
    private static final Logger log = LoggerFactory.getLogger(SignFilter.class);
    // 排除过滤的 uri 地址,nacos自行添加
    @Autowired
    private IgnoreWhiteProperties ignoreWhite;
    @Autowired
    private RedisService redisService;
    @Value("${security.sign}")
    private boolean parameter_signature;
    /**
     * 组装签名路径
     *
     * @param params
     * @return
     */
    public static String localSignUrl(JSONObject params, String key) {
        List<String> keySet = new ArrayList<>(params.keySet());
        // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
        Collections.sort(keySet, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        // 构造签名键值对的格式
        StringBuilder sb = new StringBuilder();
        for (String k : keySet) {
            String v = params.getString(k);
            if (StringUtils.isNotEmpty(v)) {
                sb.append(k + "=" + v + "&");
            }
        }
        String signUrl = sb.substring(0, sb.length() - 1);
        System.err.println("签名串:" + signUrl);
        return signUrlEncode(signUrl, key);
    }
    /**
     * 签名字符串加密
     *
     * @param signUrl
     * @param encryptKey
     * @return
     */
    public static String signUrlEncode(String signUrl, String encryptKey) {
        byte[] signByte = new byte[0];
        try {
            signByte = HMACSHA1.HmacSHA1Encrypt(signUrl, encryptKey);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        String localSign = Base64.encodeBase64String(signByte);
        return localSign;
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();
        HttpMethod method = request.getMethod();
        if (method != HttpMethod.POST) {
            return chain.filter(exchange.mutate().request(mutate.build()).build());
        }
        String sign = request.getHeaders().getFirst(TokenConstants.SIGN);
        String nonce_str = request.getHeaders().getFirst(TokenConstants.NONCE_STR);
        if (parameter_signature && StringUtils.isEmpty(sign)) {
            return unauthorizedResponse(exchange, "签名不能为空!");
        }
        if (parameter_signature && StringUtils.isEmpty(nonce_str)) {
            return unauthorizedResponse(exchange, "签名不能为空!");
        }
        if (parameter_signature) {
            return authSign(exchange, chain, sign, nonce_str);
        }
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }
    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
        log.error("[签名异常处理]请求路径:{}", exchange.getRequest().getPath());
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.BAD_REQUEST);
    }
    /**
     * 校验签名
     *
     * @return
     */
    private Mono<Void> authSign(ServerWebExchange exchange, GatewayFilterChain chain, String sign, String nonce_str) {
        return DataBufferUtils.join(exchange.getRequest().getBody())
                .flatMap(dataBuffer -> {
                    byte[] bytes = new byte[dataBuffer.readableByteCount()];
                    dataBuffer.read(bytes);
                    String bodyString = new String(bytes, StandardCharsets.UTF_8);
                    log.info("请求参数:{}", bodyString);
                    if (!authSign(JSON.parseObject(bodyString), sign, nonce_str)) {
                        return unauthorizedResponse(exchange, "签名验证失败!");
                    }
                    DataBufferUtils.release(dataBuffer);
                    Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                        DataBuffer buffer = exchange.getResponse().bufferFactory()
                                .wrap(bytes);
                        return Mono.just(buffer);
                    });
                    ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
                        @Override
                        public Flux<DataBuffer> getBody() {
                            return cachedFlux;
                        }
                    };
                    return chain.filter(exchange.mutate().request(mutatedRequest)
                            .build());
                });
    }
    /**
     * 签名校验
     *
     * @return
     */
    private boolean authSign(JSONObject jsonStr, String sign, String nonce_str) {
        System.err.println("请求签名:" + sign);
        String signUrlEncode = localSignUrl(jsonStr, nonce_str);
        signUrlEncode = signUrlEncode.replaceAll("& #40;", "\\(")
                .replaceAll("& #41;", "\\)");
        if (sign.equals(signUrlEncode)) {
            return true;
        }
        System.err.println("签名值:" + signUrlEncode);
        return false;
    }
    @Override
    public int getOrder() {
        return -200;
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java
@@ -3,6 +3,7 @@
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
@@ -24,56 +25,45 @@
 * @author ruoyi
 */
@Component
public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object>
{
    private final static String[] VALIDATE_URL = new String[] { "/auth/login", "/auth/register" };
    @Autowired
    private ValidateCodeService validateCodeService;
    @Autowired
    private CaptchaProperties captchaProperties;
    private static final String CODE = "code";
    private static final String UUID = "uuid";
    @Override
    public GatewayFilter apply(Object config)
    {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            // 非登录/注册请求或验证码关闭,不处理
            if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled())
            {
                return chain.filter(exchange);
            }
            try
            {
                String rspStr = resolveBodyFromRequest(request);
                JSONObject obj = JSON.parseObject(rspStr);
                validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID));
            }
            catch (Exception e)
            {
                return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage());
            }
            return chain.filter(exchange);
        };
    }
    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest)
    {
        // 获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        AtomicReference<String> bodyRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });
        return bodyRef.get();
    }
public class ValidateCodeFilter extends AbstractGatewayFilterFactory<Object> {
    private final static String[] VALIDATE_URL = new String[]{"/auth/login", "/auth/register"};
    private static final String CODE = "code";
    private static final String UUID = "uuid";
    @Autowired
    private ValidateCodeService validateCodeService;
    @Autowired
    private CaptchaProperties captchaProperties;
    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            // 非登录/注册请求或验证码关闭,不处理
            if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled()) {
                return chain.filter(exchange);
            }
            try {
                String rspStr = resolveBodyFromRequest(request);
                JSONObject obj = JSON.parseObject(rspStr);
                validateCodeService.checkCaptcha(obj.getString(CODE), obj.getString(UUID));
            } catch (Exception e) {
                return ServletUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage());
            }
            return chain.filter(exchange);
        };
    }
    private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
        // 获取请求体
        Flux<DataBuffer> body = serverHttpRequest.getBody();
        AtomicReference<String> bodyRef = new AtomicReference<>();
        body.subscribe(buffer -> {
            CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
            DataBufferUtils.release(buffer);
            bodyRef.set(charBuffer.toString());
        });
        return bodyRef.get();
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java
@@ -44,93 +44,87 @@
 */
@Component
@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true")
public class XssFilter implements GlobalFilter, Ordered
{
    private static final Logger log = LoggerFactory.getLogger(XssFilter.class);
    // 跨站脚本的 xss 配置,nacos自行添加
    @Autowired
    private XssProperties xss;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        // xss开关未开启 或 通过nacos关闭,不过滤
        if (!xss.getEnabled()) {
            return chain.filter(exchange);
        }
        // GET DELETE 不过滤
        HttpMethod method = request.getMethod();
        if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE) {
            return chain.filter(exchange);
        }
        // 非json类型,不过滤
        if (!isJsonRequest(exchange)) {
            return chain.filter(exchange);
        }
        // excludeUrls 不过滤
        String url = request.getURI().getPath();
        if (StringUtils.matches(url, xss.getExcludeUrls())) {
            return chain.filter(exchange);
        }
        ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange);
        return chain.filter(exchange.mutate().request(httpRequestDecorator).build());
    }
    private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange) {
        ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
            @Override
            public Flux<DataBuffer> getBody() {
                Flux<DataBuffer> body = super.getBody();
                return body.buffer().map(dataBuffers -> {
                    DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                    DataBuffer join = dataBufferFactory.join(dataBuffers);
                    byte[] content = new byte[join.readableByteCount()];
                    join.read(content);
                    DataBufferUtils.release(join);
                    String bodyStr = new String(content, StandardCharsets.UTF_8);
                    // 防xss攻击过滤
                    bodyStr = EscapeUtil.clean(bodyStr);
                    // 转成字节
                    byte[] bytes = bodyStr.getBytes();
                    NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
                    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
                    buffer.write(bytes);
                    return buffer;
                });
            }
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                // 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
                httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                return httpHeaders;
            }
        };
        return serverHttpRequestDecorator;
    }
    /**
     * 是否是Json请求
     *
     * @param exchange HTTP请求
     */
    public boolean isJsonRequest(ServerWebExchange exchange) {
        String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
        return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
    }
    @Override
    public int getOrder()
    {
        return -100;
    }
public class XssFilter implements GlobalFilter, Ordered {
    private static final Logger log = LoggerFactory.getLogger(XssFilter.class);
    // 跨站脚本的 xss 配置,nacos自行添加
    @Autowired
    private XssProperties xss;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        // xss开关未开启 或 通过nacos关闭,不过滤
        if (!xss.getEnabled()) {
            return chain.filter(exchange);
        }
        // GET DELETE 不过滤
        HttpMethod method = request.getMethod();
        if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE) {
            return chain.filter(exchange);
        }
        // 非json类型,不过滤
        if (!isJsonRequest(exchange)) {
            return chain.filter(exchange);
        }
        // excludeUrls 不过滤
        String url = request.getURI().getPath();
        if (StringUtils.matches(url, xss.getExcludeUrls())) {
            return chain.filter(exchange);
        }
        ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange);
        return chain.filter(exchange.mutate().request(httpRequestDecorator).build());
    }
    private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange) {
        ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
            @Override
            public Flux<DataBuffer> getBody() {
                Flux<DataBuffer> body = super.getBody();
                return body.buffer().map(dataBuffers -> {
                    DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                    DataBuffer join = dataBufferFactory.join(dataBuffers);
                    byte[] content = new byte[join.readableByteCount()];
                    join.read(content);
                    DataBufferUtils.release(join);
                    String bodyStr = new String(content, StandardCharsets.UTF_8);
                    // 防xss攻击过滤
                    bodyStr = EscapeUtil.clean(bodyStr);
                    // 转成字节
                    byte[] bytes = bodyStr.getBytes();
                    NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
                    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
                    buffer.write(bytes);
                    return buffer;
                });
            }
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                // 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length
                httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                return httpHeaders;
            }
        };
        return serverHttpRequestDecorator;
    }
    /**
     * 是否是Json请求
     *
     * @param exchange HTTP请求
     */
    public boolean isJsonRequest(ServerWebExchange exchange) {
        String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
        return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
    }
    @Override
    public int getOrder() {
        return -100;
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/GatewayExceptionHandler.java
@@ -19,38 +19,30 @@
 */
@Order(-1)
@Configuration
public class GatewayExceptionHandler implements ErrorWebExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)
    {
        ServerHttpResponse response = exchange.getResponse();
        if (exchange.getResponse().isCommitted())
        {
            return Mono.error(ex);
        }
        String msg;
        if (ex instanceof NotFoundException)
        {
            msg = "服务未找到";
        }
        else if (ex instanceof ResponseStatusException)
        {
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;
            msg = responseStatusException.getMessage();
        }
        else
        {
            msg = "内部服务器错误";
        }
        log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
        return ServletUtils.webFluxResponseWriter(response, msg);
    }
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse response = exchange.getResponse();
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        }
        String msg;
        if (ex instanceof NotFoundException) {
            msg = "服务未找到";
        } else if (ex instanceof ResponseStatusException) {
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;
            msg = responseStatusException.getMessage();
        } else {
            msg = "内部服务器错误";
        }
        log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage());
        return ServletUtils.webFluxResponseWriter(response, msg);
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SentinelFallbackHandler.java
@@ -13,29 +13,23 @@
 *
 * @author ruoyi
 */
public class SentinelFallbackHandler implements WebExceptionHandler
{
    private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange)
    {
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍候再试");
    }
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)
    {
        if (exchange.getResponse().isCommitted())
        {
            return Mono.error(ex);
        }
        if (!BlockException.isBlockException(ex))
        {
            return Mono.error(ex);
        }
        return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
    }
    private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable)
    {
        return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
    }
public class SentinelFallbackHandler implements WebExceptionHandler {
    private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求超过最大数,请稍候再试");
    }
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        }
        if (!BlockException.isBlockException(ex)) {
            return Mono.error(ex);
        }
        return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
    }
    private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
        return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/SwaggerHandler.java
@@ -1,6 +1,7 @@
package com.ruoyi.gateway.handler;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -16,41 +17,34 @@
@RestController
@RequestMapping("/swagger-resources")
public class SwaggerHandler
{
    @Autowired(required = false)
    private SecurityConfiguration securityConfiguration;
    @Autowired(required = false)
    private UiConfiguration uiConfiguration;
    private final SwaggerResourcesProvider swaggerResources;
    @Autowired
    public SwaggerHandler(SwaggerResourcesProvider swaggerResources)
    {
        this.swaggerResources = swaggerResources;
    }
    @GetMapping("/configuration/security")
    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration()
    {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
                HttpStatus.OK));
    }
    @GetMapping("/configuration/ui")
    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration()
    {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
    }
    @SuppressWarnings("rawtypes")
    @GetMapping("")
    public Mono<ResponseEntity> swaggerResources()
    {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }
public class SwaggerHandler {
    private final SwaggerResourcesProvider swaggerResources;
    @Autowired(required = false)
    private SecurityConfiguration securityConfiguration;
    @Autowired(required = false)
    private UiConfiguration uiConfiguration;
    @Autowired
    public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
        this.swaggerResources = swaggerResources;
    }
    @GetMapping("/configuration/security")
    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
                HttpStatus.OK));
    }
    @GetMapping("/configuration/ui")
    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
        return Mono.just(new ResponseEntity<>(
                Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
    }
    @SuppressWarnings("rawtypes")
    @GetMapping("")
    public Mono<ResponseEntity> swaggerResources() {
        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java
@@ -1,6 +1,7 @@
package com.ruoyi.gateway.handler;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
@@ -19,23 +20,18 @@
 * @author ruoyi
 */
@Component
public class ValidateCodeHandler implements HandlerFunction<ServerResponse>
{
    @Autowired
    private ValidateCodeService validateCodeService;
    @Override
    public Mono<ServerResponse> handle(ServerRequest serverRequest)
    {
        AjaxResult ajax;
        try
        {
            ajax = validateCodeService.createCaptcha();
        }
        catch (CaptchaException | IOException e)
        {
            return Mono.error(e);
        }
        return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax));
    }
public class ValidateCodeHandler implements HandlerFunction<ServerResponse> {
    @Autowired
    private ValidateCodeService validateCodeService;
    @Override
    public Mono<ServerResponse> handle(ServerRequest serverRequest) {
        AjaxResult ajax;
        try {
            ajax = validateCodeService.createCaptcha();
        } catch (CaptchaException | IOException e) {
            return Mono.error(e);
        }
        return ServerResponse.status(HttpStatus.OK).body(BodyInserters.fromValue(ajax));
    }
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java
@@ -1,6 +1,7 @@
package com.ruoyi.gateway.service;
import java.io.IOException;
import com.ruoyi.common.core.exception.CaptchaException;
import com.ruoyi.common.core.web.domain.AjaxResult;
@@ -9,15 +10,14 @@
 *
 * @author ruoyi
 */
public interface ValidateCodeService
{
    /**
     * 生成验证码
     */
    public AjaxResult createCaptcha() throws IOException, CaptchaException;
    /**
     * 校验验证码
     */
    public void checkCaptcha(String key, String value) throws CaptchaException;
public interface ValidateCodeService {
    /**
     * 生成验证码
     */
    public AjaxResult createCaptcha() throws IOException, CaptchaException;
    /**
     * 校验验证码
     */
    public void checkCaptcha(String key, String value) throws CaptchaException;
}
ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java
@@ -5,6 +5,7 @@
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.FastByteArrayOutputStream;
@@ -26,94 +27,81 @@
 * @author ruoyi
 */
@Service
public class ValidateCodeServiceImpl implements ValidateCodeService
{
    @Resource(name = "captchaProducer")
    private Producer captchaProducer;
    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;
    @Autowired
    private RedisService redisService;
    @Autowired
    private CaptchaProperties captchaProperties;
    /**
     * 生成验证码
     */
    @Override
    public AjaxResult createCaptcha() throws IOException, CaptchaException
    {
        AjaxResult ajax = AjaxResult.success();
        boolean captchaEnabled = captchaProperties.getEnabled();
        ajax.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled)
        {
            return ajax;
        }
        // 保存验证码信息
        String uuid = IdUtils.simpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        String capStr = null, code = null;
        BufferedImage image = null;
        String captchaType = captchaProperties.getType();
        // 生成验证码
        if ("math".equals(captchaType))
        {
            String capText = captchaProducerMath.createText();
            capStr = capText.substring(0, capText.lastIndexOf("@"));
            code = capText.substring(capText.lastIndexOf("@") + 1);
            image = captchaProducerMath.createImage(capStr);
        }
        else if ("char".equals(captchaType))
        {
            capStr = code = captchaProducer.createText();
            image = captchaProducer.createImage(capStr);
        }
        redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        // 转换流信息写出
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try
        {
            ImageIO.write(image, "jpg", os);
        }
        catch (IOException e)
        {
            return AjaxResult.error(e.getMessage());
        }
        ajax.put("uuid", uuid);
        ajax.put("img", Base64.encode(os.toByteArray()));
        return ajax;
    }
    /**
     * 校验验证码
     */
    @Override
    public void checkCaptcha(String code, String uuid) throws CaptchaException
    {
        if (StringUtils.isEmpty(code))
        {
            throw new CaptchaException("验证码不能为空");
        }
        if (StringUtils.isEmpty(uuid))
        {
            throw new CaptchaException("验证码已失效");
        }
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        String captcha = redisService.getCacheObject(verifyKey);
        redisService.deleteObject(verifyKey);
        if (!code.equalsIgnoreCase(captcha))
        {
            throw new CaptchaException("验证码错误");
        }
    }
public class ValidateCodeServiceImpl implements ValidateCodeService {
    @Resource(name = "captchaProducer")
    private Producer captchaProducer;
    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;
    @Autowired
    private RedisService redisService;
    @Autowired
    private CaptchaProperties captchaProperties;
    /**
     * 生成验证码
     */
    @Override
    public AjaxResult createCaptcha() throws IOException, CaptchaException {
        AjaxResult ajax = AjaxResult.success();
        boolean captchaEnabled = captchaProperties.getEnabled();
        ajax.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled) {
            return ajax;
        }
        // 保存验证码信息
        String uuid = IdUtils.simpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        String capStr = null, code = null;
        BufferedImage image = null;
        String captchaType = captchaProperties.getType();
        // 生成验证码
        if ("math".equals(captchaType)) {
            String capText = captchaProducerMath.createText();
            capStr = capText.substring(0, capText.lastIndexOf("@"));
            code = capText.substring(capText.lastIndexOf("@") + 1);
            image = captchaProducerMath.createImage(capStr);
        } else if ("char".equals(captchaType)) {
            capStr = code = captchaProducer.createText();
            image = captchaProducer.createImage(capStr);
        }
        redisService.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        // 转换流信息写出
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try {
            ImageIO.write(image, "jpg", os);
        } catch (IOException e) {
            return AjaxResult.error(e.getMessage());
        }
        ajax.put("uuid", uuid);
        ajax.put("img", Base64.encode(os.toByteArray()));
        return ajax;
    }
    /**
     * 校验验证码
     */
    @Override
    public void checkCaptcha(String code, String uuid) throws CaptchaException {
        if (StringUtils.isEmpty(code)) {
            throw new CaptchaException("验证码不能为空");
        }
        if (StringUtils.isEmpty(uuid)) {
            throw new CaptchaException("验证码已失效");
        }
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        String captcha = redisService.getCacheObject(verifyKey);
        redisService.deleteObject(verifyKey);
        if (!code.equalsIgnoreCase(captcha)) {
            throw new CaptchaException("验证码错误");
        }
    }
}
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppCouponController.java
@@ -56,6 +56,18 @@
    @Autowired
    private ChargingOrderClient chargingOrderClient;
    /**
     * 小程序扫一扫 添加车辆
     * @param dto
     * @return
     */
    @ApiOperation(value = "添加车辆", tags = {"小程序-扫一扫"})
    @PostMapping(value = "/scan/addCar")
    public AjaxResult addCar(@RequestBody TAppUserCar dto) {
        dto.setAppUserId(tokenService.getLoginUserApplet().getUserId());
        appUserCarService.save(dto);
        return AjaxResult.success();
    }
    /**
     * 查询用户可用优惠券数量
     * @return
     */
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserController.java
@@ -16,7 +16,9 @@
import com.ruoyi.account.wx.model.WeixinProperties;
import com.ruoyi.account.wx.tools.WxAppletTools;
import com.ruoyi.account.util.GiveVipUtil;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.bean.BeanUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.domain.BasePojo;
@@ -41,6 +43,7 @@
import lombok.extern.slf4j.Slf4j;
import org.aspectj.weaver.loadtime.Aj;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
@@ -88,10 +91,6 @@
    private TokenService tokenService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private WeixinProperties wxConfig;
    @Autowired
    private RestTemplate wxRestTemplate;
    @Resource
    private  TAppUserSignService signService;
@@ -444,6 +443,24 @@
        return R.ok();
    }
    @ApiOperation(value = "更换手机号", tags = {"小程序-用户管理-更换手机号"})
    @PostMapping(value = "/user/updatePhone")
    public AjaxResult<String> updatePhone(@Validated @RequestBody UpdatePhoneDTO dto) {
        String code = redisService.getCacheObject(dto.getPhone() + Constants.APPLET);
        if(StringUtils.isEmpty(code)){
            return AjaxResult.error("验证码已过期,请重新获取验证码!");
        }
        if(!code.equals(dto.getCode())){
            return AjaxResult.error("验证码错误!");
        }
        // 获取当前用户信息
        Long userId = tokenService.getLoginUserApplet().getUserId();
        TAppUser appUser = appUserService.getById(userId);
        appUser.setPhone(dto.getPhone());
        appUserService.updateById(appUser);
        return AjaxResult.success();
    }
    /**
     * 根据用户id查询用户信息
     * @param appUserIds 用户id
@@ -479,6 +496,17 @@
        return R.ok();
    }
    /**
     * 通过手机号查询用户
     * @param phone
     * @return
     */
    @GetMapping("/user/selectByPhone")
    public R<TAppUser> selectByPhone(@RequestParam("phone") String phone){
        return R.ok(appUserService.getOne(Wrappers.lambdaQuery(TAppUser.class)
                .eq(TAppUser::getPhone,phone)
                .last("LIMIT 1")));
    }
//    @ApiOperation(value = "签到", tags = {"小程序-个人中心-签到"})
//    @PostMapping(value = "/user/sign")
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TInvoiceInformationController.java
@@ -1,8 +1,16 @@
package com.ruoyi.account.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.account.api.model.TInvoiceInformation;
import com.ruoyi.account.service.TInvoiceInformationService;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.security.service.TokenService;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
 * <p>
@@ -16,5 +24,72 @@
@RequestMapping("/t-invoice-information")
public class TInvoiceInformationController {
    @Resource
    private TInvoiceInformationService invoiceInformationService;
    @Resource
    private TokenService tokenService;
    @ResponseBody
    @GetMapping(value = "/getInvoiceInformationList")
    @ApiOperation(value = "获取开票抬头数据列表", tags = {"小程序-充电发票"})
    public AjaxResult<List<TInvoiceInformation>> getInvoiceInformationList(){
        Long userId = tokenService.getLoginUserApplet().getUserId();
        List<TInvoiceInformation> list = invoiceInformationService.list(new LambdaQueryWrapper<TInvoiceInformation>().eq(TInvoiceInformation::getAppUserId, userId).eq(TInvoiceInformation::getDelFlag, 0));
        return AjaxResult.success(list);
    }
    @ResponseBody
    @PostMapping(value = "/addInvoiceInformation")
    @ApiOperation(value = "添加开票抬头数据", tags = {"小程序-充电发票"})
    public AjaxResult addInvoiceInformation(@RequestBody TInvoiceInformation invoiceInformation){
        Long userId = tokenService.getLoginUserApplet().getUserId();
        //如果当前是默认抬头,则需要去除其他的默认配置
        if(1 == invoiceInformation.getIsDefault()){
            TInvoiceInformation one = invoiceInformationService.getOne(new LambdaQueryWrapper<TInvoiceInformation>().eq(TInvoiceInformation::getDelFlag, 0)
                    .eq(TInvoiceInformation::getIsDefault, 1).eq(TInvoiceInformation::getAppUserId, userId));
            if(null != one){
                one.setIsDefault(0);
                invoiceInformationService.updateById(one);
            }
        }
        invoiceInformation.setAppUserId(userId);
        invoiceInformationService.save(invoiceInformation);
        return AjaxResult.success();
    }
    @ResponseBody
    @GetMapping(value = "/getInvoiceInformationInfo/{id}")
    @ApiOperation(value = "获取开票抬头详情数据", tags = {"小程序-充电发票"})
    public AjaxResult<TInvoiceInformation> getInvoiceInformationInfo(@PathVariable String id){
        TInvoiceInformation information = invoiceInformationService.getById(id);
        return AjaxResult.success(information);
    }
    @ResponseBody
    @PostMapping(value = "/editInvoiceInformation")
    @ApiOperation(value = "编辑开票抬头数据", tags = {"小程序-充电发票"})
    public AjaxResult editInvoiceInformation(@RequestBody TInvoiceInformation invoiceInformation){
        Long userId = tokenService.getLoginUserApplet().getUserId();
        //如果当前是默认抬头,则需要去除其他的默认配置
        if(1 == invoiceInformation.getIsDefault()){
            TInvoiceInformation one = invoiceInformationService.getOne(new LambdaQueryWrapper<TInvoiceInformation>().eq(TInvoiceInformation::getDelFlag, 0)
                    .eq(TInvoiceInformation::getIsDefault, 1).eq(TInvoiceInformation::getAppUserId, userId));
            if(null != one && !one.getId().equals(invoiceInformation.getId())){
                one.setIsDefault(0);
                invoiceInformationService.updateById(one);
            }
        }
        invoiceInformationService.updateById(invoiceInformation);
        return AjaxResult.success();
    }
}
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/TAppUserService.java
@@ -38,4 +38,10 @@
     * @return
     */
    Map<String, Object> getUserInfo(TAppUser appUser);
    /**
     * 账号判断
     * @param status
     */
    public void throwInfo(Integer status);
}
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/TAppUserServiceImpl.java
@@ -11,6 +11,7 @@
import com.ruoyi.account.service.TAppUserService;
import com.ruoyi.account.wx.model.WeixinProperties;
import com.ruoyi.account.wx.pojo.AppletUserDecodeData;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.system.api.model.LoginUserApplet;
import org.springframework.beans.factory.annotation.Autowired;
@@ -51,6 +52,9 @@
                appUser.setPhone(appletUserDecodeData.getPhoneNumber());
            }
        }
        if(Objects.nonNull(appUser.getStatus())){
            throwInfo(appUser.getStatus());
        }
        appUser.setAvatar(appletUserDecodeData.getAvatarUrl());
        appUser.setCity(appletUserDecodeData.getCity());
        appUser.setName(appletUserDecodeData.getNickName());
@@ -78,6 +82,9 @@
                appUser.setPhone(userInfo.getMobile());
            }
        }
        if(Objects.nonNull(appUser.getStatus())){
            throwInfo(appUser.getStatus());
        }
        appUser.setAvatar(userInfo.getAvatar());
        appUser.setCity(userInfo.getCity());
        appUser.setName(userInfo.getNickName());
@@ -102,4 +109,16 @@
        tokenInfos.put("info",loginUserApplet);
        return tokenInfos;
    }
    @Override
    public void throwInfo(Integer status){
        switch (status){
            case 2:
                throw new ServiceException("账号被冻结,请联系管理员");
            case 3:
                throw new ServiceException("账号已注销,请重新注册使用");
            default:
                break;
        }
    }
}
ruoyi-service/ruoyi-account/src/main/resources/mapper/account/TInvoiceInformationMapper.xml
@@ -14,14 +14,14 @@
        <result column="company_phone" property="companyPhone" />
        <result column="deposit_bank" property="depositBank" />
        <result column="bank_account" property="bankAccount" />
        <result column="default" property="default" />
        <result column="is_default" property="isDefault" />
        <result column="create_time" property="createTime" />
        <result column="del_flag" property="delFlag" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, app_user_id, invoice_type, invoicing_object_type, name, tax_identification_number, company_address, company_phone, deposit_bank, bank_account, default, create_time, del_flag
        id, app_user_id, invoice_type, invoicing_object_type, name, tax_identification_number, company_address, company_phone, deposit_bank, bank_account, is_default, create_time, del_flag
    </sql>
</mapper>
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/CodeController.java
New file
@@ -0,0 +1,53 @@
package com.ruoyi.chargingPile.controller;
import com.ruoyi.account.api.feignClient.AppUserClient;
import com.ruoyi.account.api.model.TAppUser;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.service.TChargingPileNotificationService;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.constant.MsgConstants;
import com.ruoyi.common.core.utils.HttpUtils;
import com.ruoyi.common.core.utils.MsgUtil;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.redis.service.RedisService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
public class CodeController {
    @Autowired
    private RedisService redisService;
    @Autowired
    private AppUserClient appUserClient;
    @Autowired
    private TChargingPileNotificationService chargingPileNotificationService;
    /**
     * 获取验证码
     *
     * @param phone 手机号
     * @return 结果
     */
    @ApiOperation(value = "获取验证码",notes = "获取验证码",tags = {"更换手机号获取验证码"})
    @GetMapping("getCode")
    public AjaxResult getCode(@RequestParam("phone") String phone)
    {
        TAppUser appUser = appUserClient.selectByPhone(phone).getData();
        if (Objects.nonNull(appUser)){
            return AjaxResult.error("该手机号已绑定账号");
        }
        String code = MsgUtil.createCode();
        redisService.setCacheObject(phone+ Constants.APPLET,code,5L, TimeUnit.MINUTES);
        String reqStr = MsgUtil.codeMsg(phone, code);
        String result = HttpUtils.post(MsgConstants.SEND_URL, reqStr);
        // 记录短信发送
        chargingPileNotificationService.saveData(1,null,null,phone,"验证码:"+code+",用于更换手机号。请勿转发。");
        return AjaxResult.success(result);
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/SiteController.java
@@ -156,7 +156,7 @@
    
    @ResponseBody
    @PostMapping("/getSiteList")
    @PostMapping("/addSite")
    @ApiOperation(value = "添加站点", tags = {"管理后台-站点管理"})
    public AjaxResult addSite(@RequestBody Site site){
        return siteService.addSite(site);
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TAccountingStrategyController.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.api.feignClient.AppUserClient;
import com.ruoyi.chargingPile.api.dto.TAccountingStrategyDTO;
import com.ruoyi.chargingPile.api.model.*;
import com.ruoyi.chargingPile.api.query.TAccountingStrategyQuery;
@@ -15,13 +16,16 @@
import com.ruoyi.chargingPile.service.TChargingPileService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.domain.BaseDelete;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.log.enums.OperatorType;
import com.ruoyi.system.api.feignClient.SysUserClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -30,6 +34,7 @@
import java.math.BigInteger;
import java.math.RoundingMode;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
/**
@@ -51,7 +56,8 @@
    private TChargingPileService chargingPileService;
    @Autowired
    private ISiteService siteService;
    @Autowired
    private SysUserClient sysUserClient;
    @Resource
    private TokenService tokenService;
@@ -120,8 +126,16 @@
     */
    @ApiOperation(tags = {"后台-计费策略", "管理后台-站点管理"},value = "查看计费策略详情")
    @GetMapping(value = "/getDetailById")
    public AjaxResult<TAccountingStrategy> getDetailById(@RequestParam("id") Integer id) {
        return AjaxResult.ok(accountingStrategyService.getById(id));
    public AjaxResult<TAccountingStrategyVO> getDetailById(@RequestParam("id") Integer id) {
        TAccountingStrategy accountingStrategy = accountingStrategyService.getById(id);
        TAccountingStrategyVO accountingStrategyVO = new TAccountingStrategyVO();
        BeanUtils.copyProperties(accountingStrategy,accountingStrategyVO);
        // 查询用户信息
        String firstUserName = sysUserClient.getSysUser(accountingStrategy.getFirstUserId()).getData().getNickName();
        String twoUserName = sysUserClient.getSysUser(accountingStrategy.getTwoUserId()).getData().getNickName();
        accountingStrategyVO.setFirstUserName(firstUserName);
        accountingStrategyVO.setTwoUserName(twoUserName);
        return AjaxResult.ok(accountingStrategyVO);
    }
    /**
@@ -143,11 +157,12 @@
    @Log(title = "批量删除计费策略", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-计费策略"},value = "批量删除计费策略")
    @DeleteMapping(value = "/deleteByIds")
    public AjaxResult<Boolean> deleteByIds(@RequestBody List<Integer> ids) {
    public AjaxResult<Boolean> deleteByIds(@RequestParam String ids) {
        String[] split = ids.split(",");
        // 刪除计费策略明细信息
        accountingStrategyDetailService.remove(Wrappers.lambdaQuery(TAccountingStrategyDetail.class)
                .in(TAccountingStrategyDetail::getAccountingStrategyId, ids));
        return AjaxResult.ok(accountingStrategyService.removeByIds(ids));
                .in(TAccountingStrategyDetail::getAccountingStrategyId, Arrays.asList(split)));
        return AjaxResult.success(accountingStrategyService.removeByIds(Arrays.asList(split)));
    }
    
    
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TCarportController.java
@@ -8,6 +8,7 @@
import com.ruoyi.chargingPile.service.TCarportService;
import com.ruoyi.chargingPile.service.TVehicleRampService;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.domain.BaseDelete;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.log.enums.OperatorType;
@@ -16,6 +17,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
/**
@@ -98,11 +100,12 @@
    @Log(title = "批量删除车库", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-车库"},value = "批量删除车库")
    @DeleteMapping(value = "/deleteByIds")
    public AjaxResult<Boolean> deleteByIds(@RequestBody List<Integer> ids) {
    public AjaxResult<Boolean> deleteByIds(@RequestParam String ids) {
        String[] split = ids.split(",");
        // 刪除车道信息
        vehicleRampService.remove(Wrappers.lambdaQuery(TVehicleRamp.class)
                .in(TVehicleRamp::getCarportId, ids));
        return AjaxResult.ok(carportService.removeByIds(ids));
                .in(TVehicleRamp::getCarportId, Arrays.asList(split)));
        return AjaxResult.ok(carportService.removeByIds(Arrays.asList(split)));
    }
    
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TChargingGunController.java
@@ -10,6 +10,7 @@
import com.ruoyi.chargingPile.service.TChargingPileService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.domain.BaseDelete;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
@@ -21,6 +22,7 @@
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
/**
@@ -102,8 +104,9 @@
    @Log(title = "批量删除充电枪", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-充电枪"},value = "批量删除充电枪")
    @DeleteMapping(value = "/deleteByIds")
    public AjaxResult<Boolean> deleteByIds(@RequestBody List<Integer> ids) {
        return AjaxResult.ok(chargingGunService.removeByIds(ids));
    public AjaxResult<Boolean> deleteByIds(@RequestParam String ids) {
        String[] split = ids.split(",");
        return AjaxResult.ok(chargingGunService.removeByIds(Arrays.asList(split)));
    }
    /**
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TFaultMessageController.java
@@ -42,8 +42,9 @@
    @Log(title = "添加故障报修管理", businessType = BusinessType.INSERT,operatorType = OperatorType.MOBILE)
    @ApiOperation(tags = {"小程序-故障报修"},value = "添加故障报修管理")
    @PostMapping(value = "/add")
    public AjaxResult<Boolean> add(@Validated @RequestBody TFaultMessage dto) {
        return AjaxResult.ok(faultMessageService.save(dto));
    public AjaxResult<String> add(@Validated @RequestBody TFaultMessage dto) {
        faultMessageService.add(dto);
        return AjaxResult.success();
    }
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TMonitoringEquipmentController.java
@@ -7,6 +7,7 @@
import com.ruoyi.chargingPile.api.vo.TMonitoringEquipmentVO;
import com.ruoyi.chargingPile.service.TMonitoringEquipmentService;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.domain.BaseDelete;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
@@ -16,6 +17,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
/**
@@ -92,8 +94,9 @@
    @Log(title = "批量删除监控", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-监控"},value = "批量删除监控")
    @DeleteMapping(value = "/deleteByIds")
    public AjaxResult<Boolean> deleteByIds(@RequestBody List<Integer> ids) {
        return AjaxResult.ok(monitoringEquipmentService.removeByIds(ids));
    public AjaxResult<Boolean> deleteByIds(@RequestParam String ids) {
        String[] split = ids.split(",");
        return AjaxResult.ok(monitoringEquipmentService.removeByIds(Arrays.asList(split)));
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TParkingLotController.java
@@ -13,6 +13,7 @@
import com.ruoyi.chargingPile.service.TVehicleRampService;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.domain.BaseDelete;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
@@ -22,6 +23,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
/**
@@ -117,14 +119,15 @@
    @Log(title = "批量删除停车场", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-停车场"},value = "批量删除停车场")
    @DeleteMapping(value = "/deleteByIds")
    public AjaxResult<Boolean> deleteByIds(@RequestBody List<Integer> ids) {
    public AjaxResult<Boolean> deleteByIds(@RequestParam String ids) {
        String[] split = ids.split(",");
        // 刪除车道信息
        vehicleRampService.remove(Wrappers.lambdaQuery(TVehicleRamp.class)
                .in(TVehicleRamp::getParkingLotId, ids));
                .in(TVehicleRamp::getParkingLotId, Arrays.asList(split)));
        // 删除车库信息
        carportService.remove(Wrappers.lambdaQuery(TCarport.class)
                .in(TCarport::getParkingLotId, ids));
        return AjaxResult.ok(parkingLotService.removeByIds(ids));
                .in(TCarport::getParkingLotId, Arrays.asList(split)));
        return AjaxResult.ok(parkingLotService.removeByIds(Arrays.asList(split)));
    }
    /**
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/controller/TVehicleRampController.java
@@ -4,6 +4,7 @@
import com.ruoyi.chargingPile.api.model.TVehicleRamp;
import com.ruoyi.chargingPile.service.TVehicleRampService;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.domain.BaseDelete;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.log.enums.OperatorType;
@@ -12,6 +13,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
/**
@@ -79,8 +81,9 @@
    @Log(title = "批量删除车道", businessType = BusinessType.DELETE,operatorType = OperatorType.MANAGE)
    @ApiOperation(tags = {"后台-车道"},value = "批量删除车道")
    @DeleteMapping(value = "/deleteByIds")
    public AjaxResult<Boolean> deleteByIds(@RequestBody List<Integer> ids) {
        return AjaxResult.ok(vehicleRampService.removeByIds(ids));
    public AjaxResult<Boolean> deleteByIds(@RequestParam String ids) {
        String[] split = ids.split(",");
        return AjaxResult.ok(vehicleRampService.removeByIds(Arrays.asList(split)));
    }
    /**
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TChargingPileNotificationService.java
@@ -23,4 +23,13 @@
     * @return
     */
    PageInfo<TChargingPileNotification> chargingPileNotificationPageList(Integer siteId, BasePage basePage);
    /**
     *
     * @param type 1=验证码 2=停车占位 3=充电结束 4=桩故障
     * @param phone 手机号
     * @param data 内容
     */
    void saveData(Integer type,Integer siteId,Integer chargingPileId, String phone, String data);
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/TFaultMessageService.java
@@ -13,4 +13,10 @@
 */
public interface TFaultMessageService extends IService<TFaultMessage> {
    /**
     * 添加故障报修管理
     * @param dto
     * @return
     */
    void add(TFaultMessage dto);
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TChargingPileNotificationServiceImpl.java
@@ -84,4 +84,24 @@
        pageInfo.setRecords(list);
        return pageInfo;
    }
    @Override
    public void saveData(Integer type,Integer siteId,Integer chargingPileId, String phone, String data) {
        TChargingPileNotification notification = new TChargingPileNotification();
        switch (type){
            case 1:
                // 验证码
                notification.setPhone(phone);
                notification.setContent(data);
                break;
            default:
                // 停车占位
                notification.setSiteId(siteId);
                notification.setChargingPileId(chargingPileId);
                notification.setPhone(phone);
                notification.setContent(data);
                break;
        }
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TFaultMessageServiceImpl.java
@@ -1,9 +1,18 @@
package com.ruoyi.chargingPile.service.impl;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.chargingPile.api.model.TChargingPile;
import com.ruoyi.chargingPile.api.model.TFaultMessage;
import com.ruoyi.chargingPile.mapper.TFaultMessageMapper;
import com.ruoyi.chargingPile.service.ISiteService;
import com.ruoyi.chargingPile.service.TChargingPileNotificationService;
import com.ruoyi.chargingPile.service.TChargingPileService;
import com.ruoyi.chargingPile.service.TFaultMessageService;
import com.ruoyi.common.core.utils.MsgUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
@@ -14,7 +23,29 @@
 * @author xiaochen
 * @since 2024-08-08
 */
@Slf4j
@Service
public class TFaultMessageServiceImpl extends ServiceImpl<TFaultMessageMapper, TFaultMessage> implements TFaultMessageService {
    @Autowired
    private ISiteService siteService;
    @Autowired
    private TChargingPileService chargingPileService;
    @Autowired
    private TChargingPileNotificationService chargingPileNotificationService;
    @Override
    public void add(TFaultMessage dto) {
        // 故障短信提醒
        Site site = siteService.getById(dto.getSiteId());
        TChargingPile chargingPile = chargingPileService.getById(dto.getChargingPileId());
        String siteName = site.getName();
        String result = MsgUtil.faultMsg(site.getPhone(), site.getName(), chargingPile.getNumber() + "");
        log.info("故障短信提醒:{}",result);
        if(siteName.length()>10){
            siteName = siteName.substring(0,10);
        }
        chargingPileNotificationService.saveData(4,dto.getSiteId(),dto.getChargingPileId(),site.getPhone(),"检测到"+siteName+"..."+chargingPile.getNumber()+"号桩设备离线,请及时查看处理!");
        this.save(dto);
    }
}
ruoyi-service/ruoyi-chargingPile/src/main/java/com/ruoyi/chargingPile/service/impl/TMonitoringEquipmentServiceImpl.java
@@ -17,6 +17,7 @@
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.HashSet;
@@ -50,12 +51,15 @@
        Integer objectId = sysUser.getObjectId();
        // 查询管理站点下的停车场
        List<TParkingLotVO> parkingLotVOS = parkingLotService.getList(null);
        if(CollectionUtils.isEmpty(parkingLotVOS)){
            return new PageInfo<>();
        }
        List<Integer> parkingLotIds = parkingLotVOS.stream().map(TParkingLotVO::getId).collect(Collectors.toList());
        PageInfo<TMonitoringEquipmentVO> pageInfo = new PageInfo<>(query.getPageCurr(),query.getPageSize());
        List<TMonitoringEquipmentVO> list = this.baseMapper.pageList(query,pageInfo,parkingLotIds);
        for (TMonitoringEquipmentVO monitoringEquipmentVO : list) {
            TParkingLotVO tParkingLotVO = parkingLotVOS.stream().filter(park -> park.getId().equals(monitoringEquipmentVO.getParkingLotId())).findFirst().get();
            TParkingLotVO tParkingLotVO = parkingLotVOS.stream().filter(park -> monitoringEquipmentVO.getParkingLotId().equals(park.getId())).findFirst().get();
            if(null != tParkingLotVO){
                Integer siteId = tParkingLotVO.getSiteId();
                monitoringEquipmentVO.setAuthQueryInfo(roleType == 1 ? true : partnerService.authMenu(objectId, siteId, SiteMenu.PARKING_LOT_MONITOR));
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java
@@ -8,10 +8,16 @@
import com.ruoyi.common.core.web.page.BasePage;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.order.api.model.TChargingOrder;
import com.ruoyi.order.api.model.TOrderEvaluate;
import com.ruoyi.order.api.query.TChargingCountQuery;
import com.ruoyi.order.dto.GetMyChargingOrderList;
import com.ruoyi.order.dto.GetNoInvoicedOrder;
import com.ruoyi.order.dto.MyChargingOrderInfo;
import com.ruoyi.order.dto.MyChargingOrderList;
import com.ruoyi.order.dto.OrderEvaluateVo;
import com.ruoyi.order.service.TChargingOrderService;
import com.ruoyi.order.service.TOrderEvaluateService;
import com.ruoyi.order.service.TOrderEvaluateTagService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import io.swagger.annotations.ApiOperation;
@@ -39,6 +45,19 @@
    private TChargingOrderService chargingOrderService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private TOrderEvaluateService orderEvaluateService;
    @Autowired
    private TOrderEvaluateTagService orderEvaluateTagService;
    @ResponseBody
    @PostMapping(value = "/addEvaluate")
    @ApiOperation(value = "添加评价", tags = {"小程序-扫一扫"})
    public AjaxResult getMyChargingOrderList(@RequestBody OrderEvaluateVo dto){
        dto.setAppUserId(tokenService.getLoginUserApplet().getUserId());
        orderEvaluateService.addOrderEvaluate(dto);
        return AjaxResult.success();
    }
    /**
     * 查询用户最近一次充电记录使用的车辆
     * @param
@@ -115,5 +134,16 @@
        MyChargingOrderInfo myChargingOrderInfo = chargingOrderService.getMyChargingOrderInfo(id);
        return AjaxResult.success(myChargingOrderInfo);
    }
    @ResponseBody
    @GetMapping(value = "/getNoInvoicedOrder")
    @ApiOperation(value = "获取未开票的订单数据", tags = {"小程序-充电发票"})
    public AjaxResult<List<MyChargingOrderList>> getNoInvoicedOrder(@RequestBody GetNoInvoicedOrder query){
        List<MyChargingOrderList> list = chargingOrderService.getNoInvoicedOrder(query);
        return AjaxResult.success(list);
    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TExchangeOrderController.java
@@ -166,5 +166,23 @@
        return AjaxResult.success(goodsExchangeOrder);
    }
    
    @PutMapping("/confirmReceipt/{id}")
    @ApiOperation(value = "确认收货操作", tags = {"小程序-兑换记录"})
    public AjaxResult confirmReceipt(@PathVariable String id){
        TExchangeOrder tExchangeOrder = exchangeOrderService.getById(id);
        if(tExchangeOrder.getStatus() == 3){
            return AjaxResult.error("不能重复确认收货");
        }
        if(tExchangeOrder.getStatus() == 1){
            return AjaxResult.error("订单还未发货呢");
        }
        if(tExchangeOrder.getStatus() == 4){
            return AjaxResult.error("订单已取消,不允许操作。");
        }
        tExchangeOrder.setStatus(3);
        exchangeOrderService.updateById(tExchangeOrder);
        return AjaxResult.success();
    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TOrderInvoiceController.java
@@ -1,9 +1,18 @@
package com.ruoyi.order.controller;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.order.dto.AddOrderInvoice;
import com.ruoyi.order.dto.GetOrderInvoiceList;
import com.ruoyi.order.dto.MyOrderInvoiceInfo;
import com.ruoyi.order.dto.OrderInvoiceList;
import com.ruoyi.order.service.TOrderInvoiceService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
 * <p>
@@ -18,5 +27,37 @@
@RequestMapping("/t-order-invoice")
public class TOrderInvoiceController {
    @Resource
    private TOrderInvoiceService orderInvoiceService;
    @ResponseBody
    @PostMapping("/addOrderInvoice")
    @ApiOperation(value = "添加开票申请", tags = {"小程序-充电发票"})
    public AjaxResult addOrderInvoice(@RequestBody AddOrderInvoice addOrderInvoice){
        return orderInvoiceService.addOrderInvoice(addOrderInvoice);
    }
    @ResponseBody
    @GetMapping("/getMyOrderInvoiceList")
    @ApiOperation(value = "获取开票记录列表", tags = {"小程序-充电发票"})
    public AjaxResult<List<OrderInvoiceList>> getMyOrderInvoiceList(GetOrderInvoiceList query){
        List<OrderInvoiceList> myOrderInvoiceList = orderInvoiceService.getMyOrderInvoiceList(query);
        return AjaxResult.success(myOrderInvoiceList);
    }
    @ResponseBody
    @GetMapping("/getMyOrderInvoiceInfo/{id}")
    @ApiOperation(value = "获取开票记录详情", tags = {"小程序-充电发票"})
    public AjaxResult<MyOrderInvoiceInfo> getMyOrderInvoiceInfo(@PathVariable String id){
        MyOrderInvoiceInfo myOrderInvoiceInfo = orderInvoiceService.getMyOrderInvoiceInfo(id);
        return AjaxResult.success(myOrderInvoiceInfo);
    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TShoppingOrderController.java
@@ -1,9 +1,17 @@
package com.ruoyi.order.controller;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.order.api.model.TExchangeOrder;
import com.ruoyi.order.api.model.TShoppingOrder;
import com.ruoyi.order.dto.*;
import com.ruoyi.order.service.TShoppingOrderService;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
 * <p>
@@ -17,6 +25,62 @@
@RestController
@RequestMapping("/t-shopping-order")
public class TShoppingOrderController {
    @Resource
    private TShoppingOrderService shoppingOrderService;
    @GetMapping("/getMyShoppingOrderList")
    @ApiOperation(value = "获取购买订单列表", tags = {"小程序-商城购买订单"})
    public AjaxResult<List<MyShoppingOrderList>> getMyShoppingOrderList(GetMyShoppingOrderList query){
        List<MyShoppingOrderList> list = shoppingOrderService.getMyShoppingOrderList(query);
        return AjaxResult.success(list);
    }
    @GetMapping("/getMyShoppingOrderInfo/{id}")
    @ApiOperation(value = "获取购买订单详情", tags = {"小程序-商城购买订单"})
    public AjaxResult<MyShoppingOrderInfo> getMyShoppingOrderInfo(@PathVariable String id){
        MyShoppingOrderInfo info = shoppingOrderService.getMyShoppingOrderInfo(id);
        return AjaxResult.success(info);
    }
    @PutMapping("/confirmReceipt/{id}")
    @ApiOperation(value = "确认收货操作", tags = {"小程序-商城购买订单"})
    public AjaxResult confirmReceipt(@PathVariable String id){
        TShoppingOrder shoppingOrder = shoppingOrderService.getById(id);
        if(shoppingOrder.getStatus() == 3){
            return AjaxResult.error("不能重复确认收货");
        }
        if(shoppingOrder.getStatus() == 1){
            return AjaxResult.error("订单还未发货呢");
        }
        if(shoppingOrder.getStatus() == 4){
            return AjaxResult.error("订单已取消,不允许操作。");
        }
        shoppingOrder.setStatus(3);
        shoppingOrderService.updateById(shoppingOrder);
        return AjaxResult.success();
    }
    @PutMapping("/cancelOrder/{id}")
    @ApiOperation(value = "取消订单操作", tags = {"小程序-商城购买订单"})
    public AjaxResult cancelOrder(@PathVariable String id){
        return shoppingOrderService.cancelOrder(id);
    }
    @ResponseBody
    @GetMapping(value = "/getNoInvoicedOrder")
    @ApiOperation(value = "获取未开票的订单数据", tags = {"小程序-充电发票"})
    public AjaxResult<List<MyShoppingOrderList>> getNoInvoicedOrder(GetNoInvoicedOrder query){
        List<MyShoppingOrderList> list = shoppingOrderService.getNoInvoicedOrder(query);
        return AjaxResult.success(list);
    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/AddOrderInvoice.java
New file
@@ -0,0 +1,18 @@
package com.ruoyi.order.dto;
import com.ruoyi.order.api.model.TOrderInvoice;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/8/19 15:29
 */
@Data
@ApiModel
public class AddOrderInvoice extends TOrderInvoice {
    @ApiModelProperty("订单数据数组[{\"id\":111,\"amount\":30}]")
    private String orders;
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/GetMyShoppingOrderList.java
New file
@@ -0,0 +1,17 @@
package com.ruoyi.order.dto;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/8/19 13:43
 */
@Data
@ApiModel
public class GetMyShoppingOrderList extends BasePage {
    @ApiModelProperty(value = "状态(0=全部,1=待发货,2=待收货,3=已完成)")
    private Integer status;
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/GetNoInvoicedOrder.java
New file
@@ -0,0 +1,17 @@
package com.ruoyi.order.dto;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/8/19 14:33
 */
@Data
@ApiModel
public class GetNoInvoicedOrder extends BasePage {
    @ApiModelProperty("日期")
    private String month;
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/GetOrderInvoiceList.java
New file
@@ -0,0 +1,17 @@
package com.ruoyi.order.dto;
import com.ruoyi.common.core.web.page.BasePage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * @author zhibing.pu
 * @Date 2024/8/19 16:17
 */
@Data
@ApiModel
public class GetOrderInvoiceList extends BasePage {
    @ApiModelProperty("状态(1=已申请,2=开票中,3=开票成功)")
    private Integer status;
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyOrderInvoiceInfo.java
New file
@@ -0,0 +1,38 @@
package com.ruoyi.order.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
 * @author zhibing.pu
 * @Date 2024/8/19 16:58
 */
@Data
@ApiModel
public class MyOrderInvoiceInfo {
    @ApiModelProperty("订单id")
    private String id;
    @ApiModelProperty("订单号")
    private String code;
    @ApiModelProperty("发票类型")
    private String invoiceType;
    @ApiModelProperty("开票订单类型(1=充电订单,2=购物订单,3=兑换订单,4=会员订单)")
    private Integer orderType;
    @ApiModelProperty("抬头类型(1=个人,2=企业)")
    private Integer invoicingObjectType;
    @ApiModelProperty("发票金额")
    private BigDecimal totalAmount;
    @ApiModelProperty("电子发票地址")
    private String invoiceUrl;
    @ApiModelProperty(value = "状态(1=待开票,2=开票中,3=已开票)")
    private Integer status;
    @ApiModelProperty("关联订单(商城订单)")
    private List<MyShoppingOrderList> shoppingOrder;
    @ApiModelProperty("关联订单(充电订单)")
    private List<MyChargingOrderList> chargingOrder;
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyShoppingOrderInfo.java
New file
@@ -0,0 +1,56 @@
package com.ruoyi.order.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * @author zhibing.pu
 * @Date 2024/8/19 14:04
 */
@Data
@ApiModel
public class MyShoppingOrderInfo {
    @ApiModelProperty("订单id")
    private String id;
    @ApiModelProperty("状态(1=待发货,2=待收货,3=已完成,4=已取消)")
    private Integer status;
    @ApiModelProperty("收货人姓名")
    private String consignee;
    @ApiModelProperty("电话")
    private String phone;
    @ApiModelProperty("地址")
    private String address;
    @ApiModelProperty("快递公司")
    private String expressCompany;
    @ApiModelProperty("快递单号")
    private String expressNumber;
    @ApiModelProperty("商品名称")
    private String name;
    @ApiModelProperty("商品图片")
    private String imgUrl;
    @ApiModelProperty("数量")
    private Integer number;
    @ApiModelProperty("单价")
    private BigDecimal unitPrice;
    @ApiModelProperty("订单编号")
    private String code;
    @ApiModelProperty("下单时间")
    private String createTime;
    @ApiModelProperty("支付金额")
    private BigDecimal paymentAmount;
    @ApiModelProperty("备注")
    private String remark;
    @ApiModelProperty("发货时间")
    private String deliveryTime;
    @ApiModelProperty("完成时间")
    private String finishTime;
    @ApiModelProperty("优惠券类型(1=充电优惠券,2=购物优惠券)")
    private Integer couponType;
    @ApiModelProperty("优惠券有效天数")
    private Integer days;
    @ApiModelProperty("有效期截止时间")
    private String endTime;
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyShoppingOrderList.java
New file
@@ -0,0 +1,30 @@
package com.ruoyi.order.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * @author zhibing.pu
 * @Date 2024/8/19 13:45
 */
@Data
@ApiModel
public class MyShoppingOrderList {
    @ApiModelProperty(value = "订单id")
    private String id;
    @ApiModelProperty("封面图")
    private String imgUrl;
    @ApiModelProperty("商品名称")
    private String name;
    @ApiModelProperty("状态(1=待发货,2=待收货,3=已完成,4=已取消)")
    private Integer status;
    @ApiModelProperty("单价")
    private BigDecimal unitPrice;
    @ApiModelProperty("数量")
    private Integer number;
    @ApiModelProperty("支付金额")
    private BigDecimal paymentAmount;
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/OrderInvoiceList.java
New file
@@ -0,0 +1,26 @@
package com.ruoyi.order.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
 * @author zhibing.pu
 * @Date 2024/8/19 16:18
 */
@Data
@ApiModel
public class OrderInvoiceList {
    @ApiModelProperty("数据id")
    private String id;
    @ApiModelProperty("订单类型(1=充电订单,2=购物订单,3=兑换订单,4=会员订单)")
    private Integer orderType;
    @ApiModelProperty("开票金额")
    private BigDecimal totalAmount;
    @ApiModelProperty("抬头名称")
    private String name;
    @ApiModelProperty("申请时间")
    private String createTime;
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TChargingOrderMapper.java
@@ -2,7 +2,9 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.order.api.model.TChargingOrder;
import com.ruoyi.order.dto.GetNoInvoicedOrder;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
@@ -27,5 +29,17 @@
     * @param pageSize
     * @return
     */
    List<TChargingOrder> getMyChargingOrderList(Long appUserId, Integer type, Integer pageCurr, Integer pageSize);
    List<TChargingOrder> getMyChargingOrderList(@Param("appUserId") Long appUserId, @Param("type") Integer type,
                                                @Param("pageCurr") Integer pageCurr, @Param("pageSize") Integer pageSize);
    /**
     * 获取待开票订单列表
     * @param month 筛选时间2024-01-01
     * @param pageCurr
     * @param pageSize
     * @return
     */
    List<TChargingOrder> getNoInvoicedOrder(@Param("appUserId") Long appUserId, @Param("month") String month,
                                            @Param("pageCurr") Integer pageCurr, @Param("pageSize") Integer pageSize);
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TShoppingOrderMapper.java
@@ -22,4 +22,16 @@
public interface TShoppingOrderMapper extends BaseMapper<TShoppingOrder> {
    List<TActivityStatisticslVO> activityStatistics(@Param("pageInfo") PageInfo<TActivityStatisticslVO> pageInfo, @Param("req")TActivityStatisticsQuery dto);
    /**
     * 获取未开票的订单数据
     * @param appUserId
     * @param month
     * @param pageCurr
     * @param pageSize
     * @return
     */
    List<TShoppingOrder> getNoInvoicedOrder(@Param("appUserId") Long appUserId, @Param("month") String month,
                                            @Param("pageCurr") Integer pageCurr, @Param("pageSize") Integer pageSize);
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TChargingOrderService.java
@@ -4,8 +4,12 @@
import com.ruoyi.common.core.web.page.BasePage;
import com.ruoyi.order.api.model.TChargingOrder;
import com.ruoyi.order.dto.GetMyChargingOrderList;
import com.ruoyi.order.dto.GetNoInvoicedOrder;
import com.ruoyi.order.dto.MyChargingOrderInfo;
import com.ruoyi.order.dto.MyChargingOrderList;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
import java.util.Map;
/**
@@ -33,4 +37,12 @@
     * @return
     */
    MyChargingOrderInfo getMyChargingOrderInfo(String id);
    /**
     * 获取待开票订单列表
     * @param query
     * @return
     */
    List<MyChargingOrderList> getNoInvoicedOrder(GetNoInvoicedOrder query);
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TOrderInvoiceService.java
@@ -1,7 +1,14 @@
package com.ruoyi.order.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.order.api.model.TOrderInvoice;
import com.ruoyi.order.dto.AddOrderInvoice;
import com.ruoyi.order.dto.GetOrderInvoiceList;
import com.ruoyi.order.dto.MyOrderInvoiceInfo;
import com.ruoyi.order.dto.OrderInvoiceList;
import java.util.List;
/**
 * <p>
@@ -12,5 +19,28 @@
 * @since 2024-08-07
 */
public interface TOrderInvoiceService extends IService<TOrderInvoice> {
    /**
     * 添加开票申请
     * @param addOrderInvoice
     * @return
     */
    AjaxResult addOrderInvoice(AddOrderInvoice addOrderInvoice);
    /**
     * 获取小程序用户开票记录
     * @param query
     * @return
     */
    List<OrderInvoiceList> getMyOrderInvoiceList(GetOrderInvoiceList query);
    /**
     * 获取开票申请详情
     * @param id
     * @return
     */
    MyOrderInvoiceInfo getMyOrderInvoiceInfo(String id);
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/TShoppingOrderService.java
@@ -1,11 +1,20 @@
package com.ruoyi.order.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.order.api.model.TShoppingOrder;
import com.ruoyi.order.api.query.TActivityStatisticsQuery;
import com.ruoyi.order.api.vo.TActivityStatisticslVO;
import com.ruoyi.order.api.vo.TActivityVO;
import com.ruoyi.order.dto.GetMyShoppingOrderList;
import com.ruoyi.order.dto.GetNoInvoicedOrder;
import com.ruoyi.order.dto.MyShoppingOrderInfo;
import com.ruoyi.order.dto.MyShoppingOrderList;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
 * <p>
@@ -18,4 +27,36 @@
public interface TShoppingOrderService extends IService<TShoppingOrder> {
    TActivityVO activityStatistics(TActivityStatisticsQuery dto);
    /**
     * 获取小程序商城购买订单列表
     * @param query
     * @return
     */
    List<MyShoppingOrderList> getMyShoppingOrderList(GetMyShoppingOrderList query);
    /**
     * 获取购买订单详情
     * @param id
     * @return
     */
    MyShoppingOrderInfo getMyShoppingOrderInfo(String id);
    /**
     * 取消订单
     * @param id
     * @return
     */
    AjaxResult cancelOrder(String id);
    /**
     * 获取未开票的订单列表
     * @param query
     * @return
     */
    List<MyShoppingOrderList> getNoInvoicedOrder(GetNoInvoicedOrder query);
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -15,6 +15,7 @@
import com.ruoyi.order.api.model.TChargingOrder;
import com.ruoyi.order.api.model.TChargingOrderAccountingStrategy;
import com.ruoyi.order.dto.GetMyChargingOrderList;
import com.ruoyi.order.dto.GetNoInvoicedOrder;
import com.ruoyi.order.dto.MyChargingOrderInfo;
import com.ruoyi.order.dto.MyChargingOrderList;
import com.ruoyi.order.mapper.TChargingOrderMapper;
@@ -137,4 +138,33 @@
        myChargingOrderInfo.setActionable(myChargingOrderInfo.getEndTime() + 604800000L > System.currentTimeMillis() ? 0 : 1);
        return myChargingOrderInfo;
    }
    /**
     * 获取待开票订单列表
     * @param query
     * @return
     */
    @Override
    public List<MyChargingOrderList> getNoInvoicedOrder(GetNoInvoicedOrder query) {
        Long appUserId = tokenService.getLoginUserApplet().getUserId();
        List<TChargingOrder> orderList = this.baseMapper.getNoInvoicedOrder(appUserId, query.getMonth(), query.getPageCurr(), query.getPageSize());
        List<MyChargingOrderList> list = new ArrayList<>();
        for (TChargingOrder tChargingOrder : orderList) {
            MyChargingOrderList myChargingOrderList = new MyChargingOrderList();
            myChargingOrderList.setId(tChargingOrder.getId().toString());
            myChargingOrderList.setStatus(tChargingOrder.getStatus());
            Site site = siteClient.getSiteByIds(Arrays.asList(tChargingOrder.getSiteId())).getData().get(0);
            myChargingOrderList.setTitle(site.getName());
            myChargingOrderList.setChargingDegree(tChargingOrder.getChargingCapacity());
            String name = chargingGunClient.getAllName(tChargingOrder.getChargingGunId()).getData();
            myChargingOrderList.setName(name);
            myChargingOrderList.setEndMode(tChargingOrder.getEndMode());
            BigDecimal payMoney = tChargingOrder.getStatus() < 4 ? tChargingOrder.getRechargeAmount() : tChargingOrder.getPaymentAmount();
            myChargingOrderList.setPayMoney(payMoney);
            myChargingOrderList.setCreateTime(tChargingOrder.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            list.add(myChargingOrderList);
        }
        return list;
    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TOrderInvoiceServiceImpl.java
@@ -1,10 +1,42 @@
package com.ruoyi.order.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient;
import com.ruoyi.chargingPile.api.feignClient.SiteClient;
import com.ruoyi.chargingPile.api.model.Site;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.order.api.model.TChargingOrder;
import com.ruoyi.order.api.model.TOrderInvoice;
import com.ruoyi.order.api.model.TOrderInvoiceDetail;
import com.ruoyi.order.api.model.TShoppingOrder;
import com.ruoyi.order.dto.*;
import com.ruoyi.order.mapper.TOrderInvoiceMapper;
import com.ruoyi.order.service.TChargingOrderService;
import com.ruoyi.order.service.TOrderInvoiceDetailService;
import com.ruoyi.order.service.TOrderInvoiceService;
import com.ruoyi.order.service.TShoppingOrderService;
import com.ruoyi.other.api.domain.TCoupon;
import com.ruoyi.other.api.domain.TGoods;
import com.ruoyi.other.api.domain.TInvoiceType;
import com.ruoyi.other.api.feignClient.CouponClient;
import com.ruoyi.other.api.feignClient.GoodsClient;
import com.ruoyi.other.api.feignClient.InvoiceTypeClient;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
 * <p>
@@ -16,5 +48,184 @@
 */
@Service
public class TOrderInvoiceServiceImpl extends ServiceImpl<TOrderInvoiceMapper, TOrderInvoice> implements TOrderInvoiceService {
    @Resource
    private TokenService tokenService;
    @Resource
    private TOrderInvoiceDetailService orderInvoiceDetailService;
    @Resource
    private InvoiceTypeClient invoiceTypeClient;
    @Resource
    private TChargingOrderService chargingOrderService;
    @Resource
    private TShoppingOrderService shoppingOrderService;
    @Resource
    private ChargingGunClient chargingGunClient;
    @Resource
    private SiteClient siteClient;
    @Resource
    private GoodsClient goodsClient;
    @Resource
    private CouponClient couponClient;
    /**
     * 添加开票申请
     * @param addOrderInvoice
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public AjaxResult addOrderInvoice(AddOrderInvoice addOrderInvoice) {
        Long userId = tokenService.getLoginUserApplet().getUserId();
        String orders = addOrderInvoice.getOrders();
        if(StringUtils.isNotEmpty(orders)){
            return AjaxResult.error("请选择有效的订单");
        }
        JSONArray parse = JSONArray.parse(orders);
        List<Long> orderIds = new ArrayList<>();
        Map<Long, BigDecimal> map = new HashMap<>();
        for (int i = 0; i < parse.size(); i++) {
            JSONObject jsonObject = parse.getJSONObject(i);
            Long id = jsonObject.getLong("id");
            BigDecimal amount = jsonObject.getBigDecimal("amount");
            orderIds.add(id);
            map.put(id, amount);
        }
        long count = orderInvoiceDetailService.count(new LambdaQueryWrapper<TOrderInvoiceDetail>().eq(TOrderInvoiceDetail::getOrderType, addOrderInvoice.getOrderType())
                .in(TOrderInvoiceDetail::getOrderId, orderIds));
        if(count > 0){
            return AjaxResult.error("不能重复申请开票,请刷新数据后重试");
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String code = Math.random() * 1000 + sdf.format(new Date());
        addOrderInvoice.setAppUserId(userId);
        addOrderInvoice.setCode(code);
        addOrderInvoice.setStatus(1);
        this.save(addOrderInvoice);
        //获取开票类型
        TInvoiceType invoiceType = invoiceTypeClient.getInvoiceType(addOrderInvoice.getInvoiceTypeId()).getData();
        for (Long orderId : orderIds) {
            TOrderInvoiceDetail orderInvoiceDetail = new TOrderInvoiceDetail();
            orderInvoiceDetail.setOrderInvoiceId(addOrderInvoice.getId());
            orderInvoiceDetail.setInvoiceAmount(map.get(orderId));
            orderInvoiceDetail.setOrderType(addOrderInvoice.getOrderType());
            orderInvoiceDetail.setOrderId(orderId);
            orderInvoiceDetail.setElectricityTariff(invoiceType.getElectricityTariff());
            orderInvoiceDetail.setServiceTariff(invoiceType.getServiceTariff());
            orderInvoiceDetail.setAddedServiceTariff(invoiceType.getAddedServiceTariff());
            orderInvoiceDetailService.save(orderInvoiceDetail);
        }
        return AjaxResult.success();
    }
    /**
     * 获取开票记录列表
     * @param query
     * @return
     */
    @Override
    public List<OrderInvoiceList> getMyOrderInvoiceList(GetOrderInvoiceList query) {
        Long userId = tokenService.getLoginUserApplet().getUserId();
        List<TOrderInvoice> list = this.list(new LambdaQueryWrapper<TOrderInvoice>().eq(TOrderInvoice::getAppUserId, userId)
                .eq(TOrderInvoice::getStatus, query.getStatus()).orderByDesc(TOrderInvoice::getCreateTime)
                .last(" limit " + query.getPageCurr() + ", " + query.getPageSize()));
        List<OrderInvoiceList> pageList = new ArrayList<>();
        for (TOrderInvoice tOrderInvoice : list) {
            OrderInvoiceList orderInvoiceList = new OrderInvoiceList();
            orderInvoiceList.setId(tOrderInvoice.getId().toString());
            orderInvoiceList.setOrderType(tOrderInvoice.getOrderType());
            orderInvoiceList.setTotalAmount(tOrderInvoice.getTotalAmount());
            orderInvoiceList.setName(tOrderInvoice.getName());
            orderInvoiceList.setCreateTime(tOrderInvoice.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            pageList.add(orderInvoiceList);
        }
        return pageList;
    }
    /**
     * 获取开票申请详情
     * @param id
     * @return
     */
    @Override
    public MyOrderInvoiceInfo getMyOrderInvoiceInfo(String id) {
        TOrderInvoice orderInvoice = this.getById(id);
        MyOrderInvoiceInfo myOrderInvoiceInfo = new MyOrderInvoiceInfo();
        myOrderInvoiceInfo.setId(id);
        myOrderInvoiceInfo.setCode(orderInvoice.getCode());
        myOrderInvoiceInfo.setInvoiceType(orderInvoice.getInvoiceType());
        myOrderInvoiceInfo.setOrderType(orderInvoice.getOrderType());
        myOrderInvoiceInfo.setInvoicingObjectType(orderInvoice.getInvoicingObjectType());
        myOrderInvoiceInfo.setTotalAmount(orderInvoice.getTotalAmount());
        myOrderInvoiceInfo.setInvoiceUrl(orderInvoice.getInvoiceUrl());
        myOrderInvoiceInfo.setStatus(orderInvoice.getStatus());
        Integer orderType = orderInvoice.getOrderType();
        List<TOrderInvoiceDetail> list = orderInvoiceDetailService.list(new LambdaQueryWrapper<TOrderInvoiceDetail>().eq(TOrderInvoiceDetail::getOrderInvoiceId, id));
        List<Long> orderIds = list.stream().map(TOrderInvoiceDetail::getOrderId).collect(Collectors.toList());
        //充电订单
        if(orderType == 1){
            List<TChargingOrder> orderList = chargingOrderService.listByIds(orderIds);
            List<MyChargingOrderList> chargingOrder = new ArrayList<>();
            for (TChargingOrder tChargingOrder : orderList) {
                MyChargingOrderList myChargingOrderList = new MyChargingOrderList();
                myChargingOrderList.setId(tChargingOrder.getId().toString());
                myChargingOrderList.setStatus(tChargingOrder.getStatus());
                Site site = siteClient.getSiteByIds(Arrays.asList(tChargingOrder.getSiteId())).getData().get(0);
                myChargingOrderList.setTitle(site.getName());
                myChargingOrderList.setChargingDegree(tChargingOrder.getChargingCapacity());
                String name = chargingGunClient.getAllName(tChargingOrder.getChargingGunId()).getData();
                myChargingOrderList.setName(name);
                myChargingOrderList.setEndMode(tChargingOrder.getEndMode());
                BigDecimal payMoney = tChargingOrder.getStatus() < 4 ? tChargingOrder.getRechargeAmount() : tChargingOrder.getPaymentAmount();
                myChargingOrderList.setPayMoney(payMoney);
                myChargingOrderList.setCreateTime(tChargingOrder.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                chargingOrder.add(myChargingOrderList);
            }
            myOrderInvoiceInfo.setChargingOrder(chargingOrder);
        }
        //购物订单
        if(orderType == 2){
            List<TShoppingOrder> orderList = shoppingOrderService.listByIds(orderIds);
            List<MyShoppingOrderList> shoppingOrder = new ArrayList<>();
            for (TShoppingOrder tShoppingOrder : orderList) {
                MyShoppingOrderList myShoppingOrderList = new MyShoppingOrderList();
                myShoppingOrderList.setId(tShoppingOrder.getId().toString());
                String name = "";
                String imgUrl = "";
                if(tShoppingOrder.getOrderType() == 1){
                    TGoods goods = goodsClient.getGoodsById(tShoppingOrder.getGoodsId()).getData();
                    name = goods.getName();
                    imgUrl = goods.getCoverPicture();
                }else{
                    TCoupon coupon = couponClient.getCouponById1(tShoppingOrder.getGoodsId()).getData();
                    name = coupon.getName();
                    imgUrl = coupon.getCoverPicture();
                }
                myShoppingOrderList.setName(name);
                myShoppingOrderList.setImgUrl(imgUrl);
                myShoppingOrderList.setStatus(tShoppingOrder.getStatus());
                BigDecimal unitPrice = tShoppingOrder.getPaymentAmount().divide(new BigDecimal(tShoppingOrder.getPurchaseQuantity())).setScale(2, BigDecimal.ROUND_HALF_EVEN);
                myShoppingOrderList.setUnitPrice(unitPrice);
                myShoppingOrderList.setNumber(tShoppingOrder.getPurchaseQuantity());
                myShoppingOrderList.setPaymentAmount(tShoppingOrder.getPaymentAmount());
                shoppingOrder.add(myShoppingOrderList);
            }
            myOrderInvoiceInfo.setShoppingOrder(shoppingOrder);
        }
        return myOrderInvoiceInfo;
    }
}
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TShoppingOrderServiceImpl.java
@@ -1,17 +1,31 @@
package com.ruoyi.order.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.api.feignClient.AppUserAddressClient;
import com.ruoyi.account.api.model.TAppUserAddress;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.order.api.model.TExchangeOrder;
import com.ruoyi.order.api.model.TShoppingOrder;
import com.ruoyi.order.api.query.TActivityStatisticsQuery;
import com.ruoyi.order.api.vo.TActivityStatisticslVO;
import com.ruoyi.order.api.vo.TActivityVO;
import com.ruoyi.order.dto.*;
import com.ruoyi.order.mapper.TShoppingOrderMapper;
import com.ruoyi.order.service.TShoppingOrderService;
import com.ruoyi.other.api.domain.TCoupon;
import com.ruoyi.other.api.domain.TGoods;
import com.ruoyi.other.api.feignClient.CouponClient;
import com.ruoyi.other.api.feignClient.GoodsClient;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
/**
@@ -24,6 +38,21 @@
 */
@Service
public class TShoppingOrderServiceImpl extends ServiceImpl<TShoppingOrderMapper, TShoppingOrder> implements TShoppingOrderService {
    @Resource
    private TokenService tokenService;
    @Resource
    private GoodsClient goodsClient;
    @Resource
    private CouponClient couponClient;
    @Resource
    private AppUserAddressClient appUserAddressClient;
    @Override
    public TActivityVO activityStatistics(TActivityStatisticsQuery dto) {
@@ -121,4 +150,163 @@
        res.setGrantVip(grantVip);
        return res;
    }
    /**
     * 获取小程序商城购买订单列表
     * @param query
     * @return
     */
    @Override
    public List<MyShoppingOrderList> getMyShoppingOrderList(GetMyShoppingOrderList query) {
        Long userId = tokenService.getLoginUserApplet().getUserId();
        LambdaQueryWrapper<TShoppingOrder> wrapper = new LambdaQueryWrapper<TShoppingOrder>().eq(TShoppingOrder::getDelFlag, 0)
                .eq(TShoppingOrder::getAppUserId, userId);
        if(query.getStatus() != 0){
            wrapper.eq(TShoppingOrder::getStatus, query.getStatus());
        }
        List<TShoppingOrder> list = this.list(wrapper.orderByDesc(TShoppingOrder::getCreateTime).last(" limit " + query.getPageCurr() + ", " + query.getPageSize()));
        List<MyShoppingOrderList> pageList = new ArrayList<>();
        for (TShoppingOrder tShoppingOrder : list) {
            MyShoppingOrderList myShoppingOrderList = new MyShoppingOrderList();
            myShoppingOrderList.setId(tShoppingOrder.getId().toString());
            String name = "";
            String imgUrl = "";
            if(tShoppingOrder.getOrderType() == 1){
                TGoods goods = goodsClient.getGoodsById(tShoppingOrder.getGoodsId()).getData();
                name = goods.getName();
                imgUrl = goods.getCoverPicture();
            }else{
                TCoupon coupon = couponClient.getCouponById1(tShoppingOrder.getGoodsId()).getData();
                name = coupon.getName();
                imgUrl = coupon.getCoverPicture();
            }
            myShoppingOrderList.setName(name);
            myShoppingOrderList.setImgUrl(imgUrl);
            myShoppingOrderList.setStatus(tShoppingOrder.getStatus());
            BigDecimal unitPrice = tShoppingOrder.getPaymentAmount().divide(new BigDecimal(tShoppingOrder.getPurchaseQuantity())).setScale(2, BigDecimal.ROUND_HALF_EVEN);
            myShoppingOrderList.setUnitPrice(unitPrice);
            myShoppingOrderList.setNumber(tShoppingOrder.getPurchaseQuantity());
            myShoppingOrderList.setPaymentAmount(tShoppingOrder.getPaymentAmount());
            pageList.add(myShoppingOrderList);
        }
        return pageList;
    }
    /**
     * 获取购买订单详情
     * @param id
     * @return
     */
    @Override
    public MyShoppingOrderInfo getMyShoppingOrderInfo(String id) {
        TShoppingOrder shoppingOrder = this.getById(id);
        MyShoppingOrderInfo info = new MyShoppingOrderInfo();
        info.setId(id);
        info.setStatus(shoppingOrder.getStatus());
        TAppUserAddress userAddress = appUserAddressClient.getAppUserAddressById(shoppingOrder.getAppUserAddressId()).getData();
        info.setConsignee(userAddress.getName());
        info.setPhone(userAddress.getPhone());
        info.setAddress(userAddress.getAddress());
        info.setExpressCompany(shoppingOrder.getExpressCompany());
        info.setExpressNumber(shoppingOrder.getExpressNumber());
        String name = "";
        String imgUrl = "";
        if(shoppingOrder.getOrderType() == 1){
            TGoods goods = goodsClient.getGoodsById(shoppingOrder.getGoodsId()).getData();
            name = goods.getName();
            imgUrl = goods.getCoverPicture();
        }else{
            TCoupon coupon = couponClient.getCouponById1(shoppingOrder.getGoodsId()).getData();
            info.setCouponType(coupon.getType());
            info.setDays(coupon.getDays());
            info.setEndTime(coupon.getEndTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            name = coupon.getName();
            imgUrl = coupon.getCoverPicture();
        }
        info.setName(name);
        info.setImgUrl(imgUrl);
        info.setNumber(shoppingOrder.getPurchaseQuantity());
        BigDecimal unitPrice = shoppingOrder.getPaymentAmount().divide(new BigDecimal(shoppingOrder.getPurchaseQuantity())).setScale(2, BigDecimal.ROUND_HALF_EVEN);
        info.setUnitPrice(unitPrice);
        info.setCode(shoppingOrder.getCode());
        info.setCreateTime(shoppingOrder.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        info.setPaymentAmount(shoppingOrder.getPaymentAmount());
        info.setRemark(shoppingOrder.getRemark());
        info.setDeliveryTime(shoppingOrder.getConsignerTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        info.setFinishTime(shoppingOrder.getReceivingTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        return info;
    }
    /**
     * 取消订单
     * @param id
     * @return
     */
    @Override
    public AjaxResult cancelOrder(String id) {
        TShoppingOrder shoppingOrder = this.getById(id);
        if(shoppingOrder.getStatus() == 2){
            return AjaxResult.error("订单已发货,不能取消");
        }
        if(shoppingOrder.getStatus() == 3){
            return AjaxResult.error("订单已完成,不能取消");
        }
        if(shoppingOrder.getStatus() == 4){
            return AjaxResult.error("订单已取消,不能重复操作");
        }
        //先查询第三方订单状态订单是否退款
        //支付方式(1=微信,2=支付宝) todo 待完善
        Integer paymentType = shoppingOrder.getPaymentType();
        if(1 == paymentType){
        }
        if(2 == paymentType){
        }
        //退款成功后需要判断商品库存类型后决定是否需要回退库存
        //加redis锁处理高并发
        return AjaxResult.success();
    }
    /**
     * 获取未开票的订单列表
     * @param query
     * @return
     */
    @Override
    public List<MyShoppingOrderList> getNoInvoicedOrder(GetNoInvoicedOrder query) {
        Long userId = tokenService.getLoginUserApplet().getUserId();
        List<TShoppingOrder> list = this.baseMapper.getNoInvoicedOrder(userId, query.getMonth(), query.getPageCurr(), query.getPageSize());
        List<MyShoppingOrderList> pageList = new ArrayList<>();
        for (TShoppingOrder tShoppingOrder : list) {
            MyShoppingOrderList myShoppingOrderList = new MyShoppingOrderList();
            myShoppingOrderList.setId(tShoppingOrder.getId().toString());
            String name = "";
            String imgUrl = "";
            if(tShoppingOrder.getOrderType() == 1){
                TGoods goods = goodsClient.getGoodsById(tShoppingOrder.getGoodsId()).getData();
                name = goods.getName();
                imgUrl = goods.getCoverPicture();
            }else{
                TCoupon coupon = couponClient.getCouponById1(tShoppingOrder.getGoodsId()).getData();
                name = coupon.getName();
                imgUrl = coupon.getCoverPicture();
            }
            myShoppingOrderList.setName(name);
            myShoppingOrderList.setImgUrl(imgUrl);
            myShoppingOrderList.setStatus(tShoppingOrder.getStatus());
            BigDecimal unitPrice = tShoppingOrder.getPaymentAmount().divide(new BigDecimal(tShoppingOrder.getPurchaseQuantity())).setScale(2, BigDecimal.ROUND_HALF_EVEN);
            myShoppingOrderList.setUnitPrice(unitPrice);
            myShoppingOrderList.setNumber(tShoppingOrder.getPurchaseQuantity());
            myShoppingOrderList.setPaymentAmount(tShoppingOrder.getPaymentAmount());
            pageList.add(myShoppingOrderList);
        }
        return pageList;
    }
}
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TChargingOrderMapper.xml
@@ -55,4 +55,18 @@
            limit #{pageCurr}, #{pageSize}
        </if>
    </select>
    <select id="getNoInvoicedOrder" resultMap="BaseResultMap">
        select * from t_charging_order where del_flag = 0 and app_user_id = #{appUserId}
        <if test="null != month and '' != month">
            and DATE_FORMAT(end_time, '%Y-%m') = #{month}
        </if>
        and id not in (select order_id from t_order_invoice_detail where order_type = 1)
        order by create_time desc
        <if test="null != pageCurr and null != pageSize">
            limit #{pageCurr}, #{pageSize}
        </if>
    </select>
</mapper>
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TOrderInvoiceMapper.xml
@@ -9,6 +9,7 @@
        <result column="app_user_id" property="appUserId" />
        <result column="order_type" property="orderType" />
        <result column="invoicing_company" property="invoicingCompany" />
        <result column="invoice_type_id" property="invoiceTypeId"/>
        <result column="invoice_type" property="invoiceType" />
        <result column="invoice_material" property="invoiceMaterial" />
        <result column="invoicing_method" property="invoicingMethod" />
@@ -23,11 +24,14 @@
        <result column="invoice_url" property="invoiceUrl" />
        <result column="mailbox" property="mailbox" />
        <result column="status" property="status" />
        <result column="create_time" property="createTime" />
        <result column="billing_time" property="billingTime" />
        <result column="billing_user_id" property="billingUserId" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, code, app_user_id, order_type, invoicing_company, invoice_type, invoice_material, invoicing_method, invoicing_object_type, name, tax_identification_number, company_address, company_phone, deposit_bank, bank_account, total_amount, invoice_url, mailbox, status
        id, code, app_user_id, order_type, invoicing_company, invoice_type_id, invoice_type, invoice_material, invoicing_method, invoicing_object_type, name, tax_identification_number, company_address, company_phone, deposit_bank, bank_account, total_amount, invoice_url, mailbox, status, create_time, billing_time, billing_user_id
    </sql>
</mapper>
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TShoppingOrderMapper.xml
@@ -204,5 +204,18 @@
            </if>
        </if>
    </select>
    <select id="getNoInvoicedOrder" resultMap="BaseResultMap">
        select * from t_shopping_order where del_flag = 0 and app_user_id = #{appUserId}
        <if test="null != month and '' != month">
            and DATE_FORMAT(create_time, '%Y-%m') = #{month}
        </if>
        and id not in (select order_id from t_order_invoice_detail where order_type = 2)
        order by create_time desc
        <if test="null != pageCurr and null != pageSize">
            limit #{pageCurr}, #{pageSize}
        </if>
    </select>
</mapper>
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TAdvertisingController.java
@@ -64,7 +64,7 @@
    }
    @ApiOperation(tags = {"小程序-广告管理"},value = "广告列表查询")
    @PostMapping(value = "/list")
    @GetMapping(value = "/list")
    public AjaxResult<List<TAdvertising>> list() {
        return AjaxResult.ok(advertisingService.list(Wrappers.lambdaQuery(TAdvertising.class)
                .eq(TAdvertising::getStatus, AdvertisingStatusEnum.YES.getCode())));
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TInvoiceTypeController.java
@@ -1,6 +1,8 @@
package com.ruoyi.other.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.other.api.domain.TInvoiceType;
@@ -74,5 +76,29 @@
        }
        return AjaxResult.success();
    }
    @ResponseBody
    @DeleteMapping("/getInvoiceTypeList")
    @ApiOperation(value = "获取开票类型", tags = {"小程序-充电发票"})
    public AjaxResult<List<TInvoiceType>> getInvoiceTypeList(){
        List<TInvoiceType> list = invoiceTypeService.list(new LambdaQueryWrapper<TInvoiceType>()
                .eq(TInvoiceType::getDelFlag, 0).orderByAsc(TInvoiceType::getCreateTime));
        return AjaxResult.success(list);
    }
    /**
     * 根据id获取发票类型
     * @param id
     * @return
     */
    @ResponseBody
    @PostMapping("/getInvoiceType/{id}")
    public R<TInvoiceType> getInvoiceType(@PathVariable Integer id){
        TInvoiceType invoiceType = invoiceTypeService.getById(id);
        return R.ok(invoiceType);
    }
}