xuhy
2024-08-19 e1e93392af81a6c347d60c8eebbc8306bb074ce3
Merge remote-tracking branch 'origin/master'
68个文件已修改
1个文件已删除
13个文件已添加
3585 ■■■■■ 已修改文件
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/GiveVipDto.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/PointsQueryDto.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/TAppUserDto.java 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/UnitChangeDto.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUser.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUserSign.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TInvoiceInformation.java 6 ●●●● 补丁 | 查看 | 原始文档 | 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/TIntegralRule.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/TSystemConfiguration.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TUserTag.java 8 ●●●● 补丁 | 查看 | 原始文档 | 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-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 89 ●●●● 补丁 | 查看 | 原始文档 | 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 28 ●●●● 补丁 | 查看 | 原始文档 | 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/TAppUserController.java 211 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserTagController.java 2 ●●● 补丁 | 查看 | 原始文档 | 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/util/GiveVipUtil.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/SignDayUtil.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-account/src/main/resources/mapper/account/TInvoiceInformationMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java 19 ●●●● 补丁 | 查看 | 原始文档 | 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/config/DataSourceProxyConfig.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TActivityController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TActivityStatisticsController.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TAdvertisingController.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TCouponController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TEnterpriseUserApplicationController.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TGoodsController.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/THtmlController.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TIntegralRuleController.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TInvoiceTypeController.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TNoticeController.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TSystemConfigurationController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TVipController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/resources/bootstrap.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-other/src/main/resources/mapper/other/TUserTagMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/GiveVipDto.java
@@ -10,5 +10,5 @@
    @ApiModelProperty("1月2季3年")
    private Integer type;
    @ApiModelProperty("用户Id")
    private Long userId;
    private String userIds;
}
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/PointsQueryDto.java
@@ -7,6 +7,7 @@
@Data
public class PointsQueryDto extends BasePage {
    @ApiModelProperty("用户id")
   private   Long userId;
    @ApiModelProperty("1收入0支出")
    private    Integer type;
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/TAppUserDto.java
New file
@@ -0,0 +1,118 @@
package com.ruoyi.account.api.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
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;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
 * <p>
 *
 * </p>
 *
 * @author luodangjia
 * @since 2024-08-06
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_app_user")
@ApiModel(value="TAppUser对象", description="")
public class TAppUserDto extends BasePojo {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty(value = "主键")
    @TableId("id")
    private String id;
    @ApiModelProperty(value = "用户")
    @TableField("name")
    private String name;
    @ApiModelProperty(value = "手机号")
    @TableField("phone")
    private String phone;
    @ApiModelProperty(value = "头像")
    @TableField("avatar")
    private String avatar;
    @ApiModelProperty(value = "会员id")
    @TableField("vip_id")
    private Integer vipId;
    @ApiModelProperty(value = "会员到期时间")
    @TableField("vip_end_time")
    private LocalDateTime vipEndTime;
    @ApiModelProperty(value = "单位id")
    @TableField("company_id")
    private Integer companyId;
    @ApiModelProperty(value = "身份证号")
    @TableField("id_card")
    private String idCard;
    @ApiModelProperty(value = "认证状态(0=否,1=是)")
    @TableField("auth_status")
    private Integer authStatus;
    @ApiModelProperty(value = "微信openid")
    @TableField("wx_openid")
    private String wxOpenid;
    @ApiModelProperty(value = "支付宝openid")
    @TableField("ali_openid")
    private String aliOpenid;
    @ApiModelProperty(value = "积分")
    @TableField("points")
    private Integer points;
    @ApiModelProperty(value = "省名称")
    @TableField("province")
    private String province;
    @ApiModelProperty(value = "省区划代码")
    @TableField("province_code")
    private String provinceCode;
    @ApiModelProperty(value = "市名称")
    @TableField("city")
    private String city;
    @ApiModelProperty(value = "市区划代码")
    @TableField("city_code")
    private String cityCode;
    @ApiModelProperty(value = "状态(1=正常,2=冻结,3=注销)")
    @TableField("status")
    private Integer status;
    @ApiModelProperty(value = "最后一次登录时间")
    @TableField("last_login_time")
    private LocalDateTime lastLoginTime;
    @ApiModelProperty(value = "标签名称")
    @TableField(exist = false)
    private String tagName;
    @ApiModelProperty(value = "vip名称")
    @TableField(exist = false)
    private String vipName;
    @ApiModelProperty("累计充电数")
    @TableField(exist = false)
    private Long orderCount;
}
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/dto/UnitChangeDto.java
New file
@@ -0,0 +1,10 @@
package com.ruoyi.account.api.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class UnitChangeDto {
    private String ids;
    private Integer unitId;
}
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUser.java
@@ -32,6 +32,8 @@
    @ApiModelProperty(value = "主键")
    @TableId("id")
    private Long id;
    @TableField(exist = false)
    private String uid;
    @ApiModelProperty(value = "用户")
    @TableField("name")
ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUserSign.java
@@ -44,6 +44,9 @@
    @ApiModelProperty(value = "奖励积分")
    @TableField("reward_points")
    private Integer rewardPoints;
    @ApiModelProperty(value = "礼盒标记")
    @TableField("is_gift")
    private Integer isGift;
    @ApiModelProperty(value = "添加时间")
    @TableField("create_time")
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-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/TIntegralRule.java
@@ -48,7 +48,7 @@
    @TableField("invite_users_to_earn_points")
    private String inviteUsersToEarnPoints;
    @ApiModelProperty(value = "签到得积分{\"num1\":1,\"num2\":[{\"num1\":1,\"num2\":1}]}")
    @ApiModelProperty(value = "签到得积分{\"num1\":1,\"num2\":[\"1(多少天),2(多少分)\"]}")
    @TableField("sign_in_for_points")
    private String signInForPoints;
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/TSystemConfiguration.java
@@ -24,7 +24,7 @@
@EqualsAndHashCode(callSuper = false)
@TableName("t_system_configuration")
@ApiModel(value="TSystemConfiguration对象", description="")
public class TSystemConfiguration extends BasePojo {
public class TSystemConfiguration implements Serializable {
    private static final long serialVersionUID = 1L;
ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TUserTag.java
@@ -39,8 +39,8 @@
    private Integer standardCondition;
    @ApiModelProperty(value = "达标条件值JSON({\"day\":1,\"times\":5})")
    @TableField("condition")
    private String condition;
    @TableField("conditions")
    private String conditions;
@@ -49,6 +49,10 @@
    @TableField(exist = false)
    private Long count;
    @ApiModelProperty(value = "前端展示用")
    @TableField("type")
    private Integer type;
}
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-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
@@ -25,55 +25,50 @@
 * @author ruoyi
 */
@Configuration
public class RouterFunctionConfiguration
{
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";
    /**
     * 这里为支持的请求头,如果有自定义的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;
    @Autowired
    private ValidateCodeHandler validateCodeHandler;
    @SuppressWarnings("rawtypes")
    @Bean
    public RouterFunction routerFunction()
    {
        return RouterFunctions.route(
                RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                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);
        };
    }
    /**
     * 跨域配置
     */
    @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
@@ -1,6 +1,7 @@
package com.ruoyi.gateway.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.common.core.constant.HttpStatus;
@@ -47,13 +48,6 @@
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;
@@ -62,7 +56,7 @@
    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());
@@ -87,8 +81,8 @@
        log.error("[签名异常处理]请求路径:{}", exchange.getRequest().getPath());
        return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.BAD_REQUEST);
    }
    /**
     * 校验签名
     * @return
@@ -119,9 +113,9 @@
                            .build());
        });
    }
    /**
     * 签名校验
     * @return
@@ -137,8 +131,8 @@
        System.err.println("签名值:" + signUrlEncode);
        return false;
    }
    /**
     * 组装签名路径
     * @param params
@@ -156,6 +150,10 @@
        // 构造签名键值对的格式
        StringBuilder sb = new StringBuilder();
        for (String k : keySet) {
            Object o = params.get(k);
            if(o instanceof JSONObject || o instanceof JSONArray){
                continue;
            }
            String v = params.getString(k);
            if(StringUtils.isNotEmpty(v)){
                sb.append(k + "=" + v + "&");
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/TAppUserController.java
@@ -1,7 +1,10 @@
package com.ruoyi.account.controller;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
@@ -11,6 +14,8 @@
import com.ruoyi.account.api.model.*;
import com.ruoyi.account.api.vo.CouponListVOVO;
import com.ruoyi.account.service.*;
import com.ruoyi.account.util.PointDetailUtil;
import com.ruoyi.account.util.SignDayUtil;
import com.ruoyi.account.wx.body.resp.Code2SessionRespBody;
import com.ruoyi.account.wx.body.resq.Code2SessionResqBody;
import com.ruoyi.account.wx.model.WeixinProperties;
@@ -36,9 +41,12 @@
import com.ruoyi.order.api.model.TExchangeOrder;
import com.ruoyi.other.api.domain.TCompany;
import com.ruoyi.other.api.domain.TCoupon;
import com.ruoyi.other.api.domain.TIntegralRule;
import com.ruoyi.other.api.domain.TUserTag;
import com.ruoyi.other.api.feignClient.IntegralRuleClient;
import com.ruoyi.other.api.feignClient.OtherClient;
import com.ruoyi.system.api.domain.SysRole;
import com.ruoyi.system.api.model.LoginUser;
import com.ruoyi.system.api.model.LoginUserApplet;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
@@ -89,6 +97,8 @@
    @Resource
    private TAppUserIntegralChangeService integralChangeService;
    @Resource
    private SignDayUtil signDayUtil;
    @Resource
    private ExchangeOrderClient exchangeOrderClient;
@@ -96,6 +106,12 @@
    private TokenService tokenService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private WeixinProperties wxConfig;
    @Autowired
    private RestTemplate wxRestTemplate;
    @Resource
    private PointDetailUtil pointDetailUtil;
    @Resource
    private  TAppUserSignService signService;
@@ -103,6 +119,10 @@
    private TAppCouponService appCouponService;
    @Resource
    private TAppUserCarService carService;
    @Resource
    private IntegralRuleClient integralRuleClient;
    @ApiOperation(value = "查询当前用户是否为会员 0否1是", tags = {"小程序--查询当前用户是否为会员"})
@@ -140,7 +160,7 @@
    @ApiOperation(value = "单位下拉框", tags = {"用户管理-单位管理"})
    @PostMapping(value = "/unit/select")
    @GetMapping(value = "/unit/select")
    public R<List<TCompany>> unitSelect() {
        UnitListQueryDto unitListQueryDto = new UnitListQueryDto();
        unitListQueryDto.setPageCurr(1);
@@ -197,6 +217,52 @@
        }
        List<Integer> vipIds = new ArrayList<>();
              vipIds     = page.getRecords().stream().map(TAppUser::getVipId).collect(Collectors.toList());
        //获取会员map
        R<Map<Integer, String>> vipMap = otherClient.getVipMap(vipIds);
        //循环处理
        for (TAppUser appUser : page.getRecords()) {
            //拿到最新的tagId
            TAppUserTag one = appUserTagService.lambdaQuery().eq(TAppUserTag::getAppUserId, appUser.getId()).orderByDesc(TAppUserTag::getCreateTime).last("limit 1").one();
            if (one!=null) {
                //设置最新的tagName
                R<TUserTag> byIdTag = otherClient.getByIdTag(one.getUserTagId());
                if (byIdTag.getData() != null) {
                    appUser.setTagName(byIdTag.getData().getName());
                }
            }
            //匹配vipMap的值
            appUser.setVipName(vipMap.getData().get(appUser.getVipId()));
            //累计充电次数
            R<Long> useOrderCount = chargingOrderClient.useOrderCount(appUser.getId());
            appUser.setOrderCount(useOrderCount.getData());
            appUser.setUid(appUser.getId().toString());
        }
        return R.ok(page);
    }
    @ApiOperation(value = "会员列表", tags = {"用户管理-会员列表"})
    @PostMapping(value = "/user/vip/page")
    public R<Page<TAppUser>> vipPage(@RequestBody UserListQueryDto userListQueryDto) {
        List<Long> userIds = new ArrayList<>();
        //如果要筛选标签。用标签获取useids
        if (userListQueryDto.getUserTagId() != null){
            userIds = appUserTagService.lambdaQuery().eq(TAppUserTag::getUserTagId, userListQueryDto.getUserTagId()).list().stream().map(TAppUserTag::getAppUserId).collect(Collectors.toList());
        }
        //列表查询
        Page<TAppUser> page = appUserService.lambdaQuery()
                .like(userListQueryDto.getUserPhone() != null && !"".equals(userListQueryDto.getUserPhone()), TAppUser::getPhone, userListQueryDto.getUserPhone())
                .eq(userListQueryDto.getCompanyId() != null, TAppUser::getCompanyId, userListQueryDto.getCompanyId())
                .eq(userListQueryDto.getCityCode() != null && !"".equals(userListQueryDto.getCityCode()), TAppUser::getCityCode, userListQueryDto.getCityCode())
                .eq(userListQueryDto.getStatus() != null, TAppUser::getStatus, userListQueryDto.getStatus())
                .eq(userListQueryDto.getVipTypeId() != null, TAppUser::getVipId, userListQueryDto.getVipTypeId())
                .in(!userIds.isEmpty(),TAppUser::getId,userIds)
                .page(Page.of(userListQueryDto.getPageCurr(), userListQueryDto.getPageSize()));
        if (page.getRecords().isEmpty()){
            return R.ok(page);
        }
        List<Integer> vipIds = new ArrayList<>();
        vipIds     = page.getRecords().stream().map(TAppUser::getVipId).collect(Collectors.toList());
        //获取会员map
        R<Map<Integer, String>> vipMap = otherClient.getVipMap(vipIds);
        //循环处理
@@ -304,7 +370,7 @@
    }
    @ApiOperation(value = "用户详情", tags = {"用户管理-用户列表"})
    @PostMapping(value = "/user/detail/{id}")
    @GetMapping(value = "/user/detail/{id}")
    public R<UserDetailDto> userDetail(@PathVariable Long id) {
        TAppUser user = appUserService.getById(id);
        UserDetailDto userDetailDto =  new UserDetailDto();
@@ -325,7 +391,9 @@
        List<Integer> tagIds = appUserTagService.lambdaQuery().eq(TAppUserTag::getAppUserId, id).orderByDesc(TAppUserTag::getCreateTime).list().stream().map(TAppUserTag::getUserTagId).collect(Collectors.toList());
        R<Map<Integer, String>> tagMap = otherClient.getTagMap(tagIds);
        userDetailDto.setTagName(tagMap.getData().values().toString());
        userDetailDto.setTagName(tagMap.getData().values()
                .stream()
                .collect(Collectors.joining(",")));
        return R.ok(userDetailDto);
    }
@@ -372,6 +440,28 @@
        appUser.setStatus(userChangeDto.getStatus());
        appUserService.updateById(appUser);
        return R.ok();
    }
    @ApiOperation(value = "修改单位", tags = {"后台-用户管理-用户列表"})
    @PostMapping(value = "/user/unit/change")
    public R unitChange(@RequestBody UnitChangeDto unitChangeDto) {
        for (String s : unitChangeDto.getIds().split(",")) {
            TAppUser byId = appUserService.getById(s);
            byId.setCompanyId(unitChangeDto.getUnitId());
            appUserService.updateById(byId);
        }
    return R.ok();
    }
    @ApiOperation(value = "删除用户", tags = {"后台-用户管理-用户列表"})
    @DeleteMapping(value = "/user/delete")
    public R userDelete(String ids) {
        String[] split = ids.split(",");
        for (String s : split) {
            appUserService.removeById(s);
        }
        return R.ok();
    }
    @ApiOperation(value = "个人中心信息", tags = {"小程序-个人中心"})
@@ -428,7 +518,11 @@
    @ApiOperation(value = "赠送会员", tags = {"用户管理-用户列表"})
    @PostMapping(value = "/user/give/vip")
    public R giveVip(@RequestBody GiveVipDto  giveVipDto) {
        TAppUser nowUser = appUserService.getById(giveVipDto.getUserId());
        String[] split = giveVipDto.getUserIds().split(",");
        for (String s : split) {
        TAppUser nowUser = appUserService.getById(s);
        int plusDay = 0;
        if (giveVipDto.getType() == 1) {
@@ -444,7 +538,7 @@
        appUserService.updateById(nowUser);
        //执行一次赠送优惠卷的定时任务
        }
        return R.ok();
    }
@@ -528,10 +622,105 @@
                .last("LIMIT 1")));
    }
//    @ApiOperation(value = "签到", tags = {"小程序-个人中心-签到"})
//    @PostMapping(value = "/user/sign")
//    public R sign() {
//
//    }
    @ApiOperation(value = "签到", tags = {"小程序-个人中心-签到"})
    @PostMapping(value = "/user/sign")
    public R sign() {
        LoginUserApplet loginUserApplet = tokenService.getLoginUserApplet();
        Long userId = loginUserApplet.getUserId();
        TAppUser byId = appUserService.getById(userId);
        if (signService.lambdaQuery().eq(TAppUserSign::getSignDay, LocalDate.now()).eq(TAppUserSign::getAppUserId, userId).count()>0){
            return R.fail("今日已签到");
        }
        //签到业务
        TAppUserSign appUserSign = new TAppUserSign();
        appUserSign.setSignDay(LocalDate.now());
        appUserSign.setRewardPoints(2);
        appUserSign.setCreateTime(LocalDateTime.now());
        appUserSign.setAppUserId(userId);
        signService.save(appUserSign);
        //签到加积分记录
        R<TIntegralRule> set = integralRuleClient.getSet();
        TIntegralRule data = set.getData();
        JSONObject jsonObject = JSON.parseObject(data.getAddVehiclesEarnsPoints());
        //增加每日积分
        Integer points = 0;
        Integer point = jsonObject.getInteger("num1");
        points= points+point;
        JSONArray num2 = jsonObject.getJSONArray("num2");
        if (num2!=null) {
            //获取连续签到的规则放入map
            Map<Integer,Integer> map = new HashMap<>();
            for (Object o : num2) {
                String o1 = (String) o;
                String[] split = o1.split(",");
                map.put(Integer.parseInt(split[0]), Integer.parseInt(split[1]));
            }
            //加上今日签到,计算连续了多少天,如果到达就增加奖励的分数
            int days = signDayUtil.calculateContinuousSignDays(userId);
            Integer i = map.get(days);
            if (i!=null){
                points= points+i;
                appUserSign.setIsGift(1);
                signService.updateById(appUserSign);
            }
        }
        pointDetailUtil.addDetail(byId.getPoints(),byId.getPoints()+points,1,userId,"每日签到","");
        byId.setPoints(byId.getPoints()+points);
        appUserService.updateById(byId);
        return R.ok();
    }
    @ApiOperation(value = "添加编辑车辆", tags = {"小程序-个人中心-车辆"})
    @PostMapping(value = "/user/car/addOrUpdate")
    public R carAdd(@RequestBody TAppUserCar appUserCar) {
        LoginUserApplet loginUserApplet = tokenService.getLoginUserApplet();
        Long userId = loginUserApplet.getUserId();
        TAppUser byId = appUserService.getById(userId);
        //如果是第一次添加车辆,增加积分
        Long count = appUserCarService.lambdaQuery().eq(TAppUserCar::getAppUserId, userId).count();
        if (count==0){
            R<TIntegralRule> set = integralRuleClient.getSet();
            TIntegralRule data = set.getData();
            JSONObject jsonObject = JSON.parseObject(data.getAddVehiclesEarnsPoints());
            Integer point = 0;
            //增加车牌50分,必填
                point = point+jsonObject.getInteger("num1");
            //增加车型分
                if (StringUtils.isNotEmpty(appUserCar.getVehicleModel())){
                    point = point+jsonObject.getInteger("num2");
                }
            //增加车辆用途分
                if (StringUtils.isNotEmpty(appUserCar.getVehicleUse())){
                    point = point+jsonObject.getInteger("num3");
                }
            //增加续航分
                if (StringUtils.isNotEmpty(appUserCar.getEndurance())){
                    point = point+jsonObject.getInteger("num4");
                }
            //增加积分记录
            pointDetailUtil.addDetail(byId.getPoints(),byId.getPoints()+point,5,userId,appUserCar.getLicensePlate(),"");
            byId.setPoints(byId.getPoints()+point);
            appUserService.updateById(byId);
        }
        //
        appUserCarService.saveOrUpdate(appUserCar);
        return R.ok();
    }
}
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserTagController.java
@@ -56,7 +56,7 @@
    @ApiOperation(value = "标签删除", tags = {"用户管理-用户标签管理"})
    @DeleteMapping(value = "/tags/delete")
    public R delete(@PathVariable String ids) {
    public R delete(String ids) {
        //拿到单位列表
        String[] split = ids.split(",");
        for (String id : split) {
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/util/GiveVipUtil.java
@@ -42,7 +42,7 @@
            tAppUserVipDetail.setEndTime(LocalDateTime.now().plusMonths(plusDay).minusDays(1));
            tAppUserVipDetail.setVipId(vipId);
            R<TVip> info = vipClient.getInfo(vipId);
            R<TVip> info = vipClient.getInfo1(vipId);
            TVip vip = info.getData();
            List<SendCouponDto> javaList = JSON.parseArray(vip.getCoupon()).toJavaList(SendCouponDto.class);
ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/SignDayUtil.java
New file
@@ -0,0 +1,76 @@
package com.ruoyi.account.util;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.ruoyi.account.api.model.TAppUserSign;
import com.ruoyi.account.service.TAppUserSignService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SignDayUtil {
    // 假设这是你的 signService 接口或者实现类
    @Resource
    private TAppUserSignService signService;
    /**
     * 计算用户的最近连续签到天数
     * @param userId 用户ID
     * @return 连续签到的最大天数
     */
    public int calculateContinuousSignDays(Long userId) {
        DateTime startOfMonth = DateUtil.beginOfMonth(new Date());
        DateTime endOfMonth = DateUtil.endOfMonth(new Date());
        // 获取用户的所有签到记录
        List<TAppUserSign> signRecords = signService.lambdaQuery()
                .between(TAppUserSign::getSignDay, startOfMonth, endOfMonth)
                .eq(TAppUserSign::getAppUserId, userId)
                .orderByDesc(TAppUserSign::getSignDay)
                .list();
        // 如果没有签到记录,则返回0
        if (signRecords.isEmpty()) {
            return 0;
        }
        // 将签到日期转换为 LocalDate 列表,并按照日期排序
        List<LocalDate> signDays = signRecords.stream()
                .map(TAppUserSign::getSignDay)
                .sorted()
                .collect(Collectors.toList());
        // 计算连续签到的最大天数
        return calculateMaxContinuousSignDays(signDays);
    }
    /**
     * 根据签到日期列表计算连续签到的最大天数
     * @param signDays 签到日期列表
     * @return 最大连续签到天数
     */
    private int calculateMaxContinuousSignDays(List<LocalDate> signDays) {
        int maxContinuousDays = 0;
        int currentContinuousDays = 0;
        LocalDate lastSignDay = null;
        for (LocalDate signDay : signDays) {
            if (lastSignDay != null && signDay.equals(lastSignDay.plusDays(1))) {
                currentContinuousDays++;
            } else {
                maxContinuousDays = Math.max(maxContinuousDays, currentContinuousDays);
                currentContinuousDays = 1;
            }
            lastSignDay = signDay;
        }
        // 更新最后的连续天数
        maxContinuousDays = Math.max(maxContinuousDays, currentContinuousDays);
        return maxContinuousDays;
    }
}
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-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java
@@ -11,7 +11,9 @@
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;
@@ -112,9 +114,9 @@
                .eq(TChargingOrder::getDelFlag, 0).eq(TChargingOrder::getStatus, 3));
        return R.ok(one);
    }
    
    @ResponseBody
    @GetMapping(value = "/getMyChargingOrderList")
@@ -132,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/config/DataSourceProxyConfig.java
File was deleted
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TActivityController.java
@@ -50,6 +50,7 @@
        return AjaxResult.ok(activityService.getById(id));
    }
    @ApiOperation(tags = {"管理后台-活动管理","小程序-个人中心-活动列表"},value = "活动列表分页查询")
    @PostMapping(value = "/pageList")
    public AjaxResult<PageInfo<TActivity>> pageList(@RequestBody AdvertisingDTO dto) {
        return AjaxResult.ok(activityService.pageList(dto));
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TActivityStatisticsController.java
@@ -32,6 +32,9 @@
public class TActivityStatisticsController {
    @Autowired
    private OrderClient orderClient;
    @ApiOperation(tags = {"管理后台-活动费用统计"},value = "管理后台活动费用统计")
    @PostMapping(value = "/pageList")
    public AjaxResult<TActivityVO> pageList(@RequestBody TActivityStatisticsQuery query) {
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TAdvertisingController.java
@@ -57,6 +57,9 @@
    public AjaxResult<TAdvertising> getInfo(Integer id) {
        return AjaxResult.ok(advertisingService.getById(id));
    }
    @ApiOperation(tags = {"管理后台-广告管理"},value = "广告列表分页查询")
    @PostMapping(value = "/pageList")
    public AjaxResult<PageInfo<TAdvertising>> pageList(@RequestBody AdvertisingDTO dto) {
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TCouponController.java
@@ -45,24 +45,35 @@
    @Autowired
    private AppCouponClient appCouponClient;
    @PostMapping("/saveGoods")
    @ApiOperation(tags = {"管理后台-优惠券管理"},value = "优惠券添加")
    public AjaxResult saveActivity(@RequestBody TCoupon dto) {
        tCouponService.save(dto);
        return AjaxResult.success();
    }
    @GetMapping("/delete")
    @ApiOperation(tags = {"管理后台-优惠券管理"},value = "优惠券删除")
    public AjaxResult delete(Integer id) {
        tCouponService.removeById(id);
        return AjaxResult.success();
    }
    @PostMapping("/updateVip")
    @ApiOperation(tags = {"管理后台-优惠券管理"},value = "优惠券修改")
    public AjaxResult updateActivity(@RequestBody TCoupon dto) {
        tCouponService.updateById(dto);
        return AjaxResult.success();
    }
    @GetMapping("/getInfo")
    @ApiOperation(tags = {"管理后台-优惠券管理"},value = "优惠券查看详情")
    public AjaxResult<TCoupon> getInfo(Integer id) {
@@ -73,6 +84,9 @@
        byId.setUseCount(appCouponClient.getUseCountByCouponId(id).getData());
        return AjaxResult.ok(byId);
    }
    @PostMapping("/exchangeRecord")
    @ApiOperation(tags = {"管理后台-优惠券管理"},value = "优惠券查看详情-兑换记录")
    public AjaxResult<PageInfo<ExchangeRecordVO>> exchangeRecord(@RequestBody ExchangeRecordGoodsQuery dto) {
@@ -93,6 +107,9 @@
        }
        return AjaxResult.ok(data);
    }
    @ApiOperation(tags = {"管理后台-优惠券管理"},value = "发放优惠券")
    @GetMapping(value = "/grantCoupon")
    public AjaxResult grantCoupon(@RequestBody GrantCouponDto dto) {
@@ -111,6 +128,8 @@
        return AjaxResult.success();
    }
    @ApiOperation(tags = {"管理后台-优惠券管理"},value = "优惠券列表分页查询")
    @PostMapping(value = "/pageList")
    public AjaxResult<PageInfo<TCoupon>> pageList(@RequestBody CouponQuery dto) {
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TEnterpriseUserApplicationController.java
@@ -48,6 +48,8 @@
        return AjaxResult.ok(enterpriseUserApplicationService.save(dto));
    }
    @ApiOperation(tags = {"后台-申请表单-集团用户"},value = "集团用户列表")
    @PostMapping(value = "/page")
    public AjaxResult<Boolean> page(@RequestBody TEnterpriseUserApplication dto) {
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TGoodsController.java
@@ -30,29 +30,45 @@
    private TGoodsService goodsService;
    @Autowired
    private TActivityService activityService;
    @PostMapping("/saveGoods")
    @ApiOperation(tags = {"管理后台-商品管理"},value = "商品添加")
    public AjaxResult saveActivity(@RequestBody TGoods dto) {
        goodsService.save(dto);
        return AjaxResult.success();
    }
    @GetMapping("/delete")
    @ApiOperation(tags = {"管理后台-商品管理"},value = "商品删除")
    public AjaxResult delete(Integer id) {
        goodsService.removeById(id);
        return AjaxResult.success();
    }
    @PostMapping("/updateVip")
    @ApiOperation(tags = {"管理后台-商品管理"},value = "商品修改")
    public AjaxResult updateActivity(@RequestBody TGoods dto) {
        goodsService.updateById(dto);
        return AjaxResult.success();
    }
    @GetMapping("/getInfo")
    @ApiOperation(tags = {"管理后台-商品管理"},value = "商品查看详情")
    public AjaxResult<TGoods> getInfo(Integer id) {
        return AjaxResult.ok(goodsService.getById(id));
    }
    @ApiOperation(tags = {"管理后台-商品管理"},value = "商品列表分页查询")
    @PostMapping(value = "/pageList")
    public AjaxResult<PageInfo<TGoods>> pageList(@RequestBody GoodsDTO dto) {
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/THtmlController.java
@@ -23,6 +23,9 @@
public class THtmlController {
    @Resource
    private THtmlService htmlService;
    @ApiOperation(tags = {"后台-内容设置-协议服务"},value = "新增修改")
    @PostMapping(value = "/saveOrUpdate")
    public AjaxResult saveOrUpdate(@RequestBody THtml tHtml) {
@@ -31,7 +34,7 @@
    }
    @ApiOperation(tags = {"后台-内容设置-协议服务"},value = "查询")
    @PostMapping(value = "/selectByType/{type}")
    @GetMapping(value = "/selectByType/{type}")
    public AjaxResult selectByType(@PathVariable Integer type) {
        THtml one = htmlService.lambdaQuery().eq(THtml::getType, type).last("limit 1").one();
        return AjaxResult.success(one);
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TIntegralRuleController.java
@@ -67,6 +67,9 @@
        }
        return R.ok(g.getContent());
    }
    @GetMapping("/saveInfo")
    @ApiOperation(tags = {"管理后台-积分管理"},value = "保存积分说明")
    @ApiImplicitParams({
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;
@@ -67,12 +69,36 @@
    @ResponseBody
    @DeleteMapping("/delInvoiceType")
    @ApiOperation(value = "删除发票类型", tags = {"管理后台-发票类型管理"})
    public AjaxResult<TInvoiceType> delInvoiceType(@RequestParam("id") Integer[] id){
    public AjaxResult<TInvoiceType> delInvoiceType(Integer[] id){
        List<TInvoiceType> tInvoiceTypes = invoiceTypeService.listByIds(Arrays.asList(id));
        for (TInvoiceType invoiceType : tInvoiceTypes) {
            invoiceTypeService.removeById(invoiceType);
        }
        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);
    }
}
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TNoticeController.java
@@ -35,15 +35,27 @@
    }
    @ApiOperation(tags = {"后台-内容设置-公告管理"},value = "删除")
    @PostMapping(value = "/deleteById/{id}")
    public AjaxResult deleteById(@PathVariable Integer id) {
        noticeService.removeById(id);
    @DeleteMapping(value = "/deleteById")
    public AjaxResult deleteById(String ids) {
        String[] split = ids.split(",");
        for (String id : split) {
            noticeService.removeById(id);
        }
        return AjaxResult.success();
    }
    @ApiOperation(tags = {"后台-内容设置-公告管理"},value = "查询")
    @PostMapping(value = "/pageList")
    public AjaxResult<Page<TNotice>> authPageList(@RequestBody NoticeQueryDto query) {
        if (query.getStatus()==null){
                return AjaxResult.success(noticeService.lambdaQuery()
                        .like(query.getContent()!=null&&query.getContent()!="",TNotice::getContent,query.getContent())
                        .page(Page.of(query.getPageCurr(),query.getPageSize())));
        }
            if (query.getStatus()==0){
                return AjaxResult.success(noticeService.lambdaQuery()
                        .le(TNotice::getStartTime, LocalDateTime.now())
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TSystemConfigurationController.java
@@ -34,13 +34,15 @@
     */
    @ApiOperation(tags = {"小程序-系统设置","后台-内容设置"},value = "联系客服,查询设置")
    @GetMapping(value = "/getDetailById")
    public AjaxResult<TSystemConfiguration> getDetailById(@RequestParam(name = "type")@ApiParam(value = "1=客服信息,2=系统设置") Integer type) {
    public AjaxResult<TSystemConfiguration> getDetailById(@RequestParam("type")@ApiParam(value = "1=客服信息,2=系统设置") Integer type) {
        return AjaxResult.ok(systemConfigurationService.getOne(Wrappers.lambdaQuery(TSystemConfiguration.class)
                .eq(TSystemConfiguration::getType, type)));
    }
    @ApiOperation(tags = {"后台-内容设置"},value = "客户信息,系统内容设置")
    @GetMapping(value = "/save")
    @PostMapping(value = "/save")
    public AjaxResult getDetailById(@RequestBody TSystemConfiguration systemConfiguration) {
        systemConfigurationService.saveOrUpdate(systemConfiguration);
        return AjaxResult.success();
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TVipController.java
@@ -6,6 +6,7 @@
import com.ruoyi.account.api.dto.SendCouponDto;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.BasePage;
import com.ruoyi.common.core.web.page.PageInfo;
import com.ruoyi.other.api.domain.TCoupon;
import com.ruoyi.other.api.domain.TIntegralRule;
@@ -84,22 +85,18 @@
    public R<TVip> getInfo1(@RequestParam("id")Integer id) {
        return R.ok(vipService.getById(id));
    }
    @ApiOperation(tags = {"管理后台-会员管理"},value = "会员列表分页查询")
    @PostMapping(value = "/pageList")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageCurr", value = "分页参数,当前页码", required = true),
            @ApiImplicitParam(name = "pageSize", value = "分页参数,每页数量",required = true)
    })
    public AjaxResult<PageInfo<TVip>> pageList(Integer pageCurr,Integer pageSize) {
        return AjaxResult.ok(vipService.pageList(pageCurr,pageSize));
    public AjaxResult<PageInfo<TVip>> pageList(@RequestBody BasePage basePage) {
        return AjaxResult.ok(vipService.pageList(basePage.getPageCurr(), basePage.getPageSize()));
    }
    @ApiOperation(tags = {"会员下拉框"},value = "会员列表分页查询")
    @PostMapping(value = "/select")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageCurr", value = "分页参数,当前页码", required = true),
            @ApiImplicitParam(name = "pageSize", value = "分页参数,每页数量",required = true)
    })
    @GetMapping(value = "/select")
    public AjaxResult<List<TVip>> select() {
        return AjaxResult.ok(vipService.list());
    }
ruoyi-service/ruoyi-other/src/main/resources/bootstrap.yml
@@ -42,7 +42,7 @@
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: seata_tx_group    #此处配置自定义的seata事务分组名称
  enable-auto-data-source-proxy: true    #关闭数据库代理
  enable-auto-data-source-proxy: false    #关闭数据库代理
  service:
    vgroup-mapping:
      seata_tx_group: default
ruoyi-service/ruoyi-other/src/main/resources/mapper/other/TUserTagMapper.xml
@@ -7,14 +7,14 @@
        <id column="id" property="id" />
        <result column="name" property="name" />
        <result column="standard_condition" property="standardCondition" />
        <result column="condition" property="condition" />
        <result column="conditions" property="conditions" />
        <result column="create_time" property="createTime" />
        <result column="del_flag" property="delFlag" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, name, standard_condition, condition, create_time, del_flag
        id, name, standard_condition, conditions, create_time, del_flag
    </sql>
</mapper>