linweichao 1 周之前
父節點
當前提交
9ced291744
共有 17 個文件被更改,包括 2211 次插入1 次删除
  1. 62 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/controller/TMingOrderController.java
  2. 17 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/dao/TMingOrderMapper.java
  3. 17 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/dao/TMingProductMapper.java
  4. 7 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/dao/TMingProductUserMapper.java
  5. 128 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/entity/MingProduct.java
  6. 59 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/entity/MingProductUser.java
  7. 126 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/entity/TMingOrder.java
  8. 26 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/service/ITMingOrderService.java
  9. 18 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/service/ITMingProductService.java
  10. 179 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/service/impl/TMingOrderServiceImpl.java
  11. 27 0
      qnfhq-api/src/main/java/com/qnfhq/modules/business/service/impl/TMingProductServiceImpl.java
  12. 133 0
      qnfhq-api/src/main/java/com/qnfhq/modules/user/entity/AppUserDetail.java
  13. 2 1
      qnfhq-api/src/main/java/com/qnfhq/modules/user/service/AppUserService.java
  14. 29 0
      qnfhq-api/src/test/java/DemoApplicationTest.java
  15. 387 0
      qnfhq-common/src/main/java/com/qnfhq/common/redis/RedisCache.java
  16. 329 0
      qnfhq-common/src/main/java/com/qnfhq/common/utils/DateUtil.java
  17. 665 0
      qnfhq-common/src/main/java/com/qnfhq/common/utils/StringUtils.java

+ 62 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/controller/TMingOrderController.java

@@ -0,0 +1,62 @@
+package com.qnfhq.modules.business.controller;
+
+
+import cn.dev33.satoken.stp.StpUtil;
+import com.qnfhq.common.ApiBaseController;
+import com.qnfhq.common.redis.RedisCache;
+import com.qnfhq.common.utils.Result;
+import com.qnfhq.common.utils.StringUtils;
+import com.qnfhq.modules.business.entity.TMingOrder;
+import com.qnfhq.modules.business.service.ITMingOrderService;
+import com.qnfhq.modules.user.service.SettingService;
+import jakarta.annotation.Resource;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import org.springframework.web.bind.annotation.*;
+
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * 挖矿Controller
+ * 
+ * @author ruoyi
+ * @date 2023-07-17
+ */
+@RestController
+@RequestMapping("/api/mingOrder")
+public class TMingOrderController extends ApiBaseController
+{
+    @Autowired
+     private SettingService settingService;
+    @Autowired
+    private ITMingOrderService itMingOrderService;
+    @Resource
+    private RedisCache redisCache;
+
+
+
+    @PostMapping("/submit")
+     public Result submit(@RequestBody  TMingOrder mingOrder) {
+        Result result = new Result();
+        String keyCache = StringUtils.format("api-currency-submit:{}", StpUtil.getLoginIdAsLong());
+        if(StringUtils.isNotNull(redisCache.getCacheObject(keyCache))) {
+            return error("请勿重复操作");
+        }
+        redisCache.setCacheObject(keyCache, "1", 30, TimeUnit.SECONDS);
+
+        String msg = itMingOrderService.bugMingOrder(mingOrder.getPlanId(),mingOrder.getAmount(),getStpUserId());
+        if(!"success".equals(msg)){
+            redisCache.deleteObject(keyCache);
+
+            return result.error(msg);
+        }
+        redisCache.deleteObject(keyCache);
+        return  null;
+    }
+
+
+
+
+
+}

+ 17 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/dao/TMingOrderMapper.java

@@ -0,0 +1,17 @@
+package com.qnfhq.modules.business.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qnfhq.modules.business.entity.TMingOrder;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * mingMapper接口
+ * 
+ * @author table
+ * @date 2023-08-18
+ */
+@Mapper
+public interface TMingOrderMapper extends BaseMapper<TMingOrder>
+{
+
+}

+ 17 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/dao/TMingProductMapper.java

@@ -0,0 +1,17 @@
+package com.qnfhq.modules.business.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qnfhq.modules.business.entity.MingProduct;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * mingProductMapper接口
+ * 
+ * @author table
+ * @date 2023-08-18
+ */
+@Mapper
+public interface TMingProductMapper extends BaseMapper<MingProduct>
+{
+
+}

+ 7 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/dao/TMingProductUserMapper.java

@@ -0,0 +1,7 @@
+package com.qnfhq.modules.business.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qnfhq.modules.business.entity.MingProductUser;
+
+public interface TMingProductUserMapper extends BaseMapper<MingProductUser> {
+}

+ 128 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/entity/MingProduct.java

@@ -0,0 +1,128 @@
+package com.qnfhq.modules.business.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.data.annotation.CreatedBy;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedBy;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * mingProduct对象 t_ming_product
+ *
+ * @author table
+ * @date 2023-08-18
+ */
+@Data
+@TableName("t_ming_product")
+public class MingProduct {
+
+private static final long serialVersionUID=1L;
+
+    /**
+     * $column.columnComment
+     */
+        @TableId(value = "id",type = IdType.AUTO)
+    private Long id;
+    /**
+     * 标题
+     */
+    private String title;
+    /**
+     * 图标
+     */
+    private String icon;
+    /**
+     * 启用禁用(展示在前端)1开0关
+     */
+    private Long status;
+    /**
+     * 天数(如 7,10,30)
+     */
+    private String days;
+
+    /**
+     * 结算时间
+     */
+    private String settleDay;
+
+    /**
+     * 违约利率
+     */
+    private BigDecimal defaultOdds;
+    /**
+     * 最小日利率百分比
+     */
+    private BigDecimal minOdds;
+    /**
+     * 最大日利率百分比
+     */
+    private BigDecimal maxOdds;
+    /**
+     * 每人限购次数,0表示不限
+     */
+    private Long timeLimit;
+    /**
+     * 最小金额
+     */
+    private BigDecimal limitMin;
+    /**
+     * 最大金额
+     */
+    private BigDecimal limitMax;
+    /**
+     * 排序
+     */
+    private Long sort;
+    /**
+     *  购买次数
+     */
+    private Long buyPurchase;
+    /**
+     * 币种 
+     */
+    private String coin;
+
+    /**
+     * 汇率
+     */
+    @TableField(exist = false)
+    private BigDecimal rate;
+
+    @CreatedBy
+    @TableField(fill = FieldFill.INSERT)
+    private String createBy;
+
+    @CreatedDate
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @LastModifiedBy
+    @TableField(fill = FieldFill.UPDATE)
+    private String updateBy;
+
+    @LastModifiedDate
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+    /** 备注 */
+    private String remark;
+
+    /**
+     * 用户的项目进度
+     * @throws
+     * @author master
+     * @date 2025/6/26
+     */
+    @TableField(exist = false)
+    private String userProcess;
+
+}

+ 59 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/entity/MingProductUser.java

@@ -0,0 +1,59 @@
+package com.qnfhq.modules.business.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.qnfhq.common.entity.BaseEntity;
+import com.qnfhq.modules.user.entity.AppAssetEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 用户购买质押限制对象 t_ming_product_user
+ *
+ * @author table
+ * @date 2023-10-11
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("t_ming_product_user")
+public class MingProductUser extends BaseEntity {
+
+private static final long serialVersionUID=1L;
+
+    /**
+     * $column.columnComment
+     */
+        @TableId(value = "id",type = IdType.AUTO)
+    private Long id;
+    /**
+     * 产品id
+     */
+    private Long productId;
+    /**
+     * 玩家用户id
+     */
+    private Long appUserId;
+    /**
+     * 限购次数
+     */
+    private Long pledgeNum;
+    /**
+     *
+     */
+    private String searchValue;
+
+    @TableField(exist = false)
+    private AppAssetEntity tAppUser;
+
+    @TableField(exist = false)
+    private String coin;
+
+    @TableField(exist = false)
+    private String icon;
+
+    @TableField(exist = false)
+    private String title;
+
+}

+ 126 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/entity/TMingOrder.java

@@ -0,0 +1,126 @@
+package com.qnfhq.modules.business.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * ming对象 t_ming_order
+ *
+ * @author table
+ * @date 2023-08-18
+ */
+@Data
+@TableName("t_ming_order")
+public class TMingOrder {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * $column.columnComment
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+    /**
+     * 投资金额(分)
+     */
+    private BigDecimal amount;
+    /**
+     * 投资期限(天)
+     */
+    private Integer days;
+    /**
+     * 0 收益  1 结算 3 赎回
+     */
+    private Integer status;
+    /**
+     * 项目id
+     */
+    private Long planId;
+    /**
+     * 项目名称
+     */
+    private String planTitle;
+    /**
+     * 订单编号
+     */
+    private String orderNo;
+    /**
+     * 到期时间
+     */
+    private Date endTime;
+    /**
+     * 结算时间
+     */
+    private Date settleTime;
+    /**
+     * 累计收益
+     */
+    private BigDecimal accumulaEarn;
+    /**
+     * 最小利率
+     */
+    private BigDecimal minOdds;
+    /**
+     * 最大利率
+     */
+    private BigDecimal maxOdds;
+    /**
+     * 后台用户id
+     */
+    private String adminUserIds;
+    /**
+     * $column.columnComment
+     */
+    private String collectionOrder;
+    /**
+     * $column.columnComment
+     */
+    private Long userId;
+    /**
+     * $column.columnComment
+     */
+    private BigDecimal orderAmount;
+
+
+    private String coin;
+
+
+    @TableField(exist = false)
+    private Integer settlementType;
+    /**
+     * 结算日期 1-31
+     */
+    @TableField(exist = false)
+    private Integer settlementDay;
+
+
+    @CreatedDate
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+
+    @LastModifiedDate
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+
+    @TableField(exist = false)
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private Map<String, Object> params;
+
+    @TableField(exist = false)
+    private String logo;
+}

+ 26 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/service/ITMingOrderService.java

@@ -0,0 +1,26 @@
+package com.qnfhq.modules.business.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qnfhq.modules.business.entity.TMingOrder;
+
+
+import java.math.BigDecimal;
+
+/**
+ * mingService接口
+ * 
+ * @author table
+ * @date 2023-08-18
+ */
+public interface ITMingOrderService extends IService<TMingOrder>
+{
+    /**
+     * 购买挖矿
+     * @param planId
+     * @param amount
+     * @param userId
+     * @return
+     */
+    String bugMingOrder(Long planId, BigDecimal amount,Long userId);
+
+}

+ 18 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/service/ITMingProductService.java

@@ -0,0 +1,18 @@
+package com.qnfhq.modules.business.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qnfhq.modules.business.entity.MingProduct;
+
+import java.util.List;
+
+/**
+ * mingProductService接口
+ * 
+ * @author table
+ * @date 2023-08-18
+ */
+public interface ITMingProductService extends IService<MingProduct>
+{
+
+    MingProduct selectTMingProductById(Long planId);
+}

+ 179 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/service/impl/TMingOrderServiceImpl.java

@@ -0,0 +1,179 @@
+package com.qnfhq.modules.business.service.impl;
+
+import cn.hutool.core.date.DateTime;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qnfhq.common.utils.DateUtil;
+import com.qnfhq.common.utils.MessageUtils;
+import com.qnfhq.modules.business.dao.TMingProductUserMapper;
+import com.qnfhq.modules.business.entity.MingProduct;
+import com.qnfhq.modules.business.entity.MingProductUser;
+import com.qnfhq.modules.business.entity.TMingOrder;
+import com.qnfhq.modules.business.dao.TMingOrderMapper;
+import com.qnfhq.modules.business.service.ITMingOrderService;
+import com.qnfhq.modules.business.service.ITMingProductService;
+import com.qnfhq.modules.user.dao.AppAssetDao;
+import com.qnfhq.modules.user.entity.AppAssetEntity;
+import com.qnfhq.modules.user.entity.AppUserDetail;
+import com.qnfhq.modules.user.entity.AppUserEntity;
+import com.qnfhq.modules.user.enums.AssetEnum;
+import com.qnfhq.modules.user.service.AppUserService;
+import com.qnfhq.modules.user.service.AppWalletRecordService;
+import com.qnfhq.utils.OrderUtils;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * mingService业务层处理
+ *
+ * @author table
+ * @date 2023-08-18
+ */
+@Service
+public class TMingOrderServiceImpl extends ServiceImpl<TMingOrderMapper, TMingOrder> implements ITMingOrderService {
+    @Resource
+    private TMingOrderMapper tMingOrderMapper;
+
+    @Resource
+    private AppWalletRecordService appWalletRecordService;
+
+    @Resource
+    private AppUserService appUserService;
+
+    @Resource
+    private ITMingProductService mingProductService;
+
+    @Resource
+    private AppAssetDao appAssetDao;
+
+    @Resource
+    private TMingProductUserMapper tMingProductUserMapper;
+
+    @Override
+    public String bugMingOrder(Long planId, BigDecimal amount, Long userId) {
+        //获取用户信息
+        AppUserEntity user = appUserService.getUserByUserId(userId);
+        //获取用户详情
+        AppUserDetail tAppUserDetail = appUserService.selectUserDetailByUserId(userId);
+        Integer tradeFlag = tAppUserDetail.getTradeFlag();
+        if (null != tradeFlag) {
+            if (1 == tradeFlag) {
+                if (tAppUserDetail.getTradeMessage() == null || tAppUserDetail.getTradeMessage().equals("")) {
+                    return MessageUtils.message("user.push.message");
+                } else {
+                    return tAppUserDetail.getTradeMessage();
+                }
+            }
+        }
+
+        //获取产品信息
+        MingProduct tMingProduct = mingProductService.selectTMingProductById(planId);
+        if(tMingProduct == null) {
+            return MessageUtils.message("product.not.exist");
+        }
+
+        // 单个用户单笔下注最小金额 和最大金额
+        if (null != tMingProduct.getLimitMin()) {
+            if (amount.compareTo(tMingProduct.getLimitMin()) < 0) {
+                return MessageUtils.message("order.single.min");
+            }
+        }
+        if (null != tMingProduct.getLimitMax()) {
+            if (tMingProduct.getLimitMax().compareTo(amount) < 0) {
+                return MessageUtils.message("order.single.max");
+            }
+        }
+
+        ////判断有没有个人购买限制
+        MingProductUser tMingProductUser = tMingProductUserMapper
+                .selectOne(new LambdaQueryWrapper<MingProductUser>()
+                        .eq(MingProductUser::getProductId, planId)
+                        .eq(MingProductUser::getAppUserId, userId));
+        if (Objects.nonNull(tMingProductUser) && Objects.nonNull(tMingProductUser.getPledgeNum()))
+            tMingProduct.setTimeLimit(tMingProductUser.getPledgeNum());
+        //判断金额是否足够
+        AppAssetEntity tAppAsset = appAssetDao
+                .selectOne(new LambdaQueryWrapper<AppAssetEntity>()
+                        .eq(AppAssetEntity::getType, AssetEnum.PLATFORM_ASSETS.getCode())
+                        .eq(AppAssetEntity::getUserId, userId).eq(AppAssetEntity::getSymbol, tMingProduct.getCoin()));
+
+        // 2. 金额判断
+        if (Objects.isNull(tAppAsset)) {
+            return MessageUtils.message("order_amount_error");
+        }
+
+        if (tAppAsset.getTotal().compareTo(amount) < 0) {
+            return MessageUtils.message("order_amount_error");
+        }
+        // 3. 订单数量判断
+        long count = this.count(new LambdaQueryWrapper<TMingOrder>().eq(TMingOrder::getPlanId, tMingProduct.getId()).eq(TMingOrder::getUserId, userId));
+        if (count >= tMingProduct.getTimeLimit()) {
+            return MessageUtils.message("financial.count.max");
+        }
+        String days = tMingProduct.getDays();
+        TMingOrder mineOrder = new TMingOrder();
+        mineOrder.setUserId(userId);
+        mineOrder.setPlanId(planId);
+        Date now = new DateTime();
+        // 下单
+        String serialId = "E" + OrderUtils.generateOrderNum();
+        //  Date endTime = DateUtil.dateFormatDay(now, Integer.valueOf(days));
+        Date settleTime = DateUtil.dateFormatDay(now, Integer.valueOf(tMingProduct.getSettleDay()));
+
+        //当日利率从接口获取,现在取最小利率
+        mineOrder.setOrderNo(serialId);
+        mineOrder.setPlanId(tMingProduct.getId());
+        mineOrder.setCreateTime(new Date());
+        mineOrder.setDays(Integer.valueOf(days));
+        mineOrder.setSettleTime(settleTime);
+        //币种
+        mineOrder.setCoin(tMingProduct.getCoin());
+        mineOrder.setAmount(amount);
+        mineOrder.setAccumulaEarn(BigDecimal.ZERO);
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Date endTime = null;
+        try {
+            endTime = sdf.parse("2026-02-17");
+        } catch (Exception e) {
+//            throw new RuntimeException(e);
+        }
+        mineOrder.setEndTime(endTime);
+        mineOrder.setPlanTitle(tMingProduct.getTitle());
+        mineOrder.setMinOdds(tMingProduct.getMinOdds());
+        mineOrder.setMaxOdds(tMingProduct.getMaxOdds());
+        mineOrder.setAdminUserIds(user.getAdminParentIds());
+        mineOrder.setUserId(user.getId());
+        mineOrder.setStatus(0);
+        //  先扣钱,再下单
+
+        /*appAssetService.reduceAssetByUserId(user.getUserId(),tMingProduct.getCoin(),amount);
+        BigDecimal bigDecimal = tAppAsset.getAvailableAmount();
+         tAppAsset.setAmout(tAppAsset.getAmout().subtract(amount));
+         tAppAsset.setAvailableAmount(bigDecimal.subtract(amount));
+         appAssetService.updateTAppAsset(tAppAsset); *
+
+        appWalletRecordService.generateRecord(user.getUserId(),
+                amount,
+                RecordEnum.PLEDGE_RECHARGE.getCode(),
+                user.getLoginName(),
+                serialId,
+                "质押认购", bigDecimal, bigDecimal.subtract(amount), tMingProduct.getCoin().toLowerCase(), user.getAdminParentIds());
+        tMingOrderMapper.insert(mineOrder);
+        //质押打码
+        Setting setting = settingService.get(SettingEnum.ADD_MOSAIC_SETTING.name());
+        if (Objects.nonNull(setting)){
+            AddMosaicSetting addMosaic = JSONUtil.toBean(setting.getSettingValue(), AddMosaicSetting.class);
+            if (Objects.nonNull(addMosaic) && Objects.nonNull(addMosaic.getIsOpen()) && addMosaic.getIsOpen() && Objects.nonNull(addMosaic.getPledgeIsOpen()) && addMosaic.getPledgeIsOpen()){
+                user.setTotleAmont(user.getTotleAmont().add(mineOrder.getAmount()));
+                appUserService.updateTotleAmont(user);
+            }
+        }*/
+        return "success";
+    }
+}
+

+ 27 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/business/service/impl/TMingProductServiceImpl.java

@@ -0,0 +1,27 @@
+package com.qnfhq.modules.business.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qnfhq.modules.business.entity.MingProduct;
+import com.qnfhq.modules.business.dao.TMingProductMapper;
+import com.qnfhq.modules.business.service.ITMingProductService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+/**
+ * mingProductService业务层处理
+ * 
+ * @author table
+ * @date 2023-08-18
+ */
+@Service
+public class TMingProductServiceImpl extends ServiceImpl<TMingProductMapper, MingProduct> implements ITMingProductService
+{
+    @Resource
+    private TMingProductMapper tMingProductMapper;
+
+
+    @Override
+    public MingProduct selectTMingProductById(Long planId) {
+        return tMingProductMapper.selectById(planId);
+    }
+}

+ 133 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/user/entity/AppUserDetail.java

@@ -0,0 +1,133 @@
+package com.qnfhq.modules.user.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.qnfhq.common.entity.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 用户详细信息对象 t_app_user_detail
+ *
+ * @author table
+ * @date 2023-07-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("t_app_user_detail")
+public class AppUserDetail extends BaseEntity {
+
+private static final long serialVersionUID=1L;
+
+    /**
+     *
+     */
+    @TableId(value = "id",type = IdType.AUTO)
+    private Long id;
+    /**
+     *
+     */
+    private Long userId;
+    /**
+     * 真实姓名
+     */
+    private String realName;
+    /**
+     * 身份证号码
+     */
+    private String idCard;
+    /**
+     * 身份证正面照片
+     */
+    private String frontUrl;
+    /**
+     * 国际
+     */
+    private String country;
+    /**
+     * 1 身份证  2 护照  3其他
+     */
+    private String cardType;
+    /**
+     * 手持身份证照片
+     */
+    private String handelUrl;
+    /**
+     * 身份证反面照片
+     */
+    private String backUrl;
+    /**
+     * 用户交易密码
+     */
+    private String userTardPwd;
+    /**
+     *
+     */
+    private String searchValue;
+    /**
+     * AuditStatusEnum
+     */
+    private String auditStatusPrimary;
+    /**
+     * AuditStatusEnum
+     */
+    private String auditStatusAdvanced;
+    /**
+     * 信用分
+     */
+    private Integer credits;
+    /**
+     * 用户充值地址
+     */
+    private String userRechargeAddress;
+
+    /**
+     * 连赢场次
+     */
+    private Integer winNum;
+    /**
+     * 连输场次
+     */
+    private Integer loseNum;
+    /**
+     * 交易是否被限制 1 为限制
+     */
+    private Integer tradeFlag;
+    /**
+     * 金额是否被限制 1 为限制
+     */
+    private Integer amountFlag;
+    /**
+     * 金额限制提示语
+     */
+    private String pushMessage;
+    /**
+     * 交易限制提示语
+     */
+    private String tradeMessage;
+    /**
+     * 实名认证时间
+     */
+    private Date operateTime;
+
+    /**
+     * 重新实名认证次数
+     */
+    private Integer reKyc;
+
+    //业务字段
+    @TableField(exist = false)
+    private String flag;
+
+    //业务字段
+    @TableField(exist = false)
+    private String adminParentIds;
+
+    //业务字段  1 初级  2  高级
+    @TableField(exist = false)
+    private Integer reSetFlag;
+}

+ 2 - 1
qnfhq-api/src/main/java/com/qnfhq/modules/user/service/AppUserService.java

@@ -3,6 +3,7 @@ package com.qnfhq.modules.user.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.common.utils.Result;
 import com.qnfhq.modules.user.dto.*;
+import com.qnfhq.modules.user.entity.AppUserDetail;
 import com.qnfhq.modules.user.entity.AppUserEntity;
 import jakarta.servlet.http.HttpServletRequest;
 
@@ -73,7 +74,7 @@ public interface AppUserService extends IService<AppUserEntity> {
     Result resetPwdByEmail(ResetPwdByEmailDTO codeDTO);
     Result resetPwdByPhone(ResetPwdByPhoneDTO codeDTO);
 
-
+    AppUserDetail selectUserDetailByUserId(Long userId);
     Result checkCaptcha(CheckCaptchaDTO dto, HttpServletRequest request);
 
     Result checkPhoneCode(String codeType,String zone,String phone,String code);

+ 29 - 0
qnfhq-api/src/test/java/DemoApplicationTest.java

@@ -0,0 +1,29 @@
+import cn.hutool.core.date.DateUtil;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qnfhq.ApiApplication;
+import com.qnfhq.modules.business.dao.TMingOrderMapper;
+import com.qnfhq.modules.business.entity.TMingOrder;
+import jakarta.annotation.Resource;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@SpringBootTest(classes = ApiApplication.class)
+public class DemoApplicationTest {
+
+    @Resource
+    private TMingOrderMapper tMingOrderMapper;
+
+    @Test
+    void test2() {
+        List<TMingOrder> tMingOrders = tMingOrderMapper.selectList(new QueryWrapper<>());
+        System.out.println(tMingOrders);
+    }
+
+
+}

+ 387 - 0
qnfhq-common/src/main/java/com/qnfhq/common/redis/RedisCache.java

@@ -0,0 +1,387 @@
+package com.qnfhq.common.redis;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.core.*;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * spring redis 工具类
+ *
+ * @author ruoyi
+ **/
+@SuppressWarnings(value = {"unchecked", "rawtypes"})
+@Component
+public class RedisCache {
+    @Autowired
+    public RedisTemplate redisTemplate;
+
+    /**
+     * 获取原子自增
+     *
+     * @param key     缓存的键值
+     * @param value   缓存的值
+     * @param timeout 过期时间
+     */
+    public <T> void increment(final String key, final T value, final Integer timeout) {
+        // 3. 存入 Redis,设置初始值 + 过期时间
+        redisTemplate.opsForValue().set(key, String.valueOf(value), timeout);
+    }
+    /**
+     * 获取原子自增
+     * @param key     缓存的键值
+     * @param value   缓存的值
+     */
+    public <T> Long increment(final String key, final Long value) {
+        // 3. 存入 Redis,设置初始值 + 过期时间
+        return redisTemplate.opsForValue().increment(key, value);
+    }
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key   缓存的键值
+     * @param value 缓存的值
+     */
+    public <T> void setCacheObject(final String key, final T value) {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key      缓存的键值
+     * @param value    缓存的值
+     * @param timeout  时间
+     * @param timeUnit 时间颗粒度
+     */
+    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
+        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key     Redis键
+     * @param timeout 超时时间
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout) {
+        return expire(key, timeout, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key     Redis键
+     * @param timeout 超时时间
+     * @param unit    时间单位
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
+        return redisTemplate.expire(key, timeout, unit);
+    }
+
+    /**
+     * 获取有效时间
+     *
+     * @param key Redis键
+     * @return 有效时间
+     */
+    public long getExpire(final String key) {
+        return redisTemplate.getExpire(key);
+    }
+
+    /**
+     * 判断 key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public Boolean hasKey(String key) {
+        return redisTemplate.hasKey(key);
+    }
+
+    /**
+     * 获得缓存的基本对象。
+     *
+     * @param key 缓存键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> T getCacheObject(final String key) {
+        ValueOperations<String, T> operation = redisTemplate.opsForValue();
+        return operation.get(key);
+    }
+
+    /**
+     * 删除单个对象
+     *
+     * @param key
+     */
+    public boolean deleteObject(final String key) {
+        return redisTemplate.delete(key);
+    }
+ /*   public boolean deleteStreamObject(final String key)
+    {
+       *//* return redisTemplate.opsForStream().destroyGroup()*//*
+    }*/
+
+    /**
+     * 删除集合对象
+     *
+     * @param collection 多个对象
+     * @return
+     */
+    public boolean deleteObject(final Collection collection) {
+        return redisTemplate.delete(collection) > 0;
+    }
+
+    /**
+     * 缓存List数据
+     *
+     * @param key      缓存的键值
+     * @param dataList 待缓存的List数据
+     * @return 缓存的对象
+     */
+    public <T> long setCacheList(final String key, final List<T> dataList) {
+        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
+        return count == null ? 0 : count;
+    }
+
+    /**
+     * 获得缓存的list对象
+     *
+     * @param key 缓存的键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> List<T> getCacheList(final String key) {
+        return redisTemplate.opsForList().range(key, 0, -1);
+    }
+
+    /**
+     * 缓存Set
+     *
+     * @param key     缓存键值
+     * @param dataSet 缓存的数据
+     * @return 缓存数据的对象
+     */
+    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
+        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
+        Iterator<T> it = dataSet.iterator();
+        while (it.hasNext()) {
+            setOperation.add(it.next());
+        }
+        return setOperation;
+    }
+
+    /**
+     * 获得缓存的set
+     *
+     * @param key
+     * @return
+     */
+    public <T> Set<T> getCacheSet(final String key) {
+        return redisTemplate.opsForSet().members(key);
+    }
+
+    /**
+     * 缓存Map
+     *
+     * @param key
+     * @param dataMap
+     */
+    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
+        if (dataMap != null) {
+            redisTemplate.opsForHash().putAll(key, dataMap);
+        }
+    }
+
+    /**
+     * 获得缓存的Map
+     *
+     * @param key
+     * @return
+     */
+    public <T> Map<String, T> getCacheMap(final String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * 往Hash中存入数据
+     *
+     * @param key   Redis键
+     * @param hKey  Hash键
+     * @param value 值
+     */
+    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
+        redisTemplate.opsForHash().put(key, hKey, value);
+    }
+
+    /**
+     * 获取Hash中的数据
+     *
+     * @param key  Redis键
+     * @param hKey Hash键
+     * @return Hash中的对象
+     */
+    public <T> T getCacheMapValue(final String key, final String hKey) {
+        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
+        return opsForHash.get(key, hKey);
+    }
+
+    /**
+     * 获取多个Hash中的数据
+     *
+     * @param key   Redis键
+     * @param hKeys Hash键集合
+     * @return Hash对象集合
+     */
+    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
+        return redisTemplate.opsForHash().multiGet(key, hKeys);
+    }
+
+    /**
+     * 删除Hash中的某条数据
+     *
+     * @param key  Redis键
+     * @param hKey Hash键
+     * @return 是否成功
+     */
+    public boolean deleteCacheMapValue(final String key, final String hKey) {
+        return redisTemplate.opsForHash().delete(key, hKey) > 0;
+    }
+
+    /**
+     * 获得缓存的基本对象列表
+     *
+     * @param pattern 字符串前缀
+     * @return 对象列表
+     */
+    public Collection<String> keys(final String pattern) {
+        return redisTemplate.keys(pattern);
+    }
+
+    public List<Long> getAllActiveUserId() {
+            List<Long> userIds = new ArrayList<>();
+            Collection<String> keys = keys("active:UserId:*");
+            for (String key : keys) {
+                String substring = key.substring(14);
+                userIds.add(Long.parseLong(substring));
+            }
+            setCacheObject("active:all:", userIds, 60, TimeUnit.SECONDS);
+            return userIds;
+    }
+
+
+    public <K, V> boolean tryLock(K key, V value, long timeout) {
+        return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.MILLISECONDS));
+    }
+
+    public boolean deleteAllObject() {
+        boolean execute = (boolean) redisTemplate.execute(new RedisCallback<Object>() {
+            public String doInRedis(RedisConnection connection) throws DataAccessException {
+                connection.flushDb();
+                return "ok";
+            }
+        });
+        return execute;
+    }
+
+    /**
+     * 原子递减
+     * @param key
+     * @param value
+     * @return
+     * @author yelz
+     */
+    public <T> Long decrement(final String key, final Long value) {
+        return redisTemplate.opsForValue().decrement(key, value);
+    }
+
+    /**
+     * 查询范围
+     * @param zsetKey
+     * @param type
+     * @param start
+     * @param end
+     * @return
+     * @author yelz
+     */
+    public ArrayList<String> getRange(String zsetKey,Integer type,long start,long end) {
+        ZSetOperations<String,String> ops = redisTemplate.opsForZSet();
+        Set<String> values = null;
+        if(2 == type.intValue()) {
+            values = ops.range(zsetKey, start, end);
+        } else {
+            values = ops.reverseRange(zsetKey, start, end);
+        }
+        return values.isEmpty() ? null : new ArrayList<String>(values);
+    }
+
+    /**
+     * 按分数范围查询
+     * @param zsetKey
+     * @param min
+     * @param max
+     * @return
+     * @author yelz
+     */
+    public ArrayList<String> getRangeByScore(String zsetKey,double min,double max) {
+        ZSetOperations<String,String> ops = redisTemplate.opsForZSet();
+        Set<String> values = null;
+        values = ops.rangeByScore(zsetKey, min, max);
+        return values.isEmpty() ? null : new ArrayList<String>(values);
+    }
+
+    /**
+     * 添加
+     * @param zsetKey
+     * @param value
+     * @param score
+     * @param direction
+     * @param maxLength
+     * @return
+     * @author yelz
+     */
+    public boolean addZSet(String zsetKey,String value,double score,int direction, long maxLength) {
+        ZSetOperations<String,String> ops = redisTemplate.opsForZSet();
+        ops.add(zsetKey, value, score);
+        long size = ops.zCard(zsetKey);
+        if(size > maxLength) {
+            if(direction == 1) {
+                ops.removeRange(zsetKey,0,size-maxLength-1);
+            } else {
+                ops.removeRange(zsetKey,maxLength,size);
+            }
+
+        }
+        return true;
+    }
+
+    /**
+     * 移除
+     * @param zsetKey
+     * @param id
+     * @return
+     */
+    public Long removeZset(String zsetKey, String id) {
+        ZSetOperations<String,String> ops = redisTemplate.opsForZSet();
+        return ops.remove(zsetKey, id);
+    }
+
+    /**
+     * 返回元素个数
+     * @return
+     */
+    public Long countZset(String zsetKey) {
+        ZSetOperations<String,String> ops = redisTemplate.opsForZSet();
+        return ops.size(zsetKey);
+    }
+}
+

+ 329 - 0
qnfhq-common/src/main/java/com/qnfhq/common/utils/DateUtil.java

@@ -0,0 +1,329 @@
+package com.qnfhq.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 日期工具类
+ *
+ * @author zebra
+ *
+ */
+@Slf4j
+public class DateUtil {
+	/**
+	 * 将Date类型转换为字符串
+	 *
+	 * @param date
+	 *            日期类型
+	 * @return 日期字符串
+	 */
+	public static String format(Date date) {
+		return format(date, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	/**
+	 * 将Date类型转换为字符串
+	 *
+	 * @param date
+	 *            日期类型
+	 * @param pattern
+	 *            字符串格式
+	 * @return 日期字符串
+	 */
+	public static String format(Date date, String pattern) {
+		if (date == null) {
+			return null;
+		}
+		if (pattern.equals("") || pattern.equals("null")) {
+			pattern = "yyyy-MM-dd HH:mm:ss";
+		}
+		return new SimpleDateFormat(pattern).format(date);
+	}
+
+	/**
+	 * 将字符串转换为Date类型
+	 *
+	 * @param date
+	 *            字符串类型
+	 * @return 日期类型
+	 */
+	public static Date format(String date) {
+		return format(date, "null");
+	}
+
+	/**
+	 * 将字符串转换为Date类型
+	 *
+	 * @param date
+	 *            字符串类型
+	 * @param pattern
+	 *            格式
+	 * @return 日期类型
+	 */
+	public static Date format(String date, String pattern) {
+		if (pattern == null || pattern.equals("") || pattern.equals("null")) {
+			pattern = "yyyy-MM-dd HH:mm:ss";
+		}
+		if (date == null || date.equals("") || date.equals("null")) {
+			return new Date();
+		}
+		Date d = null;
+		try {
+			d = new SimpleDateFormat(pattern).parse(date);
+		} catch (ParseException pe) {
+			log.debug("转换日期格式错误");
+		}
+		return d;
+	}
+
+	/**
+	 * 将Date类型转换为字符串
+	 *
+	 * @param date
+	 *            日期类型
+	 * @return 日期字符串
+	 */
+	public static Date formatStartDay(Date date) {
+		String day = format(date, "yyyy-MM-dd");
+		return format(day + " 00:00:00");
+	}
+
+	public static Date formatEndDay(Date date) {
+		String day = format(date, "yyyy-MM-dd");
+		return format(day + " 23:59:59");
+	}
+
+	public static Date formatStartDay(String date) {
+		return format(date + " 00:00:00");
+	}
+
+	public static Date formatEndDay(String date) {
+		return format(date + " 23:59:59");
+	}
+
+	/**
+	 *
+	 * @Description:比较两个日期的天数差
+	 * @Check parameters by the 【caller】 or 【itself】(参数由谁校验)
+	 * @param date1
+	 * @param date2
+	 * @return
+	 */
+	public static int daysBetween(Date date1, Date date2)
+
+	{
+
+		Calendar cal = Calendar.getInstance();
+
+		cal.setTime(date1);
+
+		long time1 = cal.getTimeInMillis();
+
+		cal.setTime(date2);
+
+		long time2 = cal.getTimeInMillis();
+
+		long between_days = (time2 - time1) / (1000 * 3600 * 24);
+
+		return Integer.parseInt(String.valueOf(between_days));
+
+	}
+
+	/**
+	 * 相加月份
+	 *
+	 * @param datetime
+	 * @return
+	 */
+	public static Date dateFormat(Date datetime, Integer month) {
+		Calendar cl = Calendar.getInstance();
+		cl.setTime(datetime);
+		cl.add(Calendar.MONTH, +month);
+		datetime = cl.getTime();
+		return datetime;
+	}
+
+	/**
+	 * 相加天
+	 *
+	 * @param datetime
+	 * @return
+	 */
+	public static Date dateFormatDay(Date datetime, Integer day) {
+		Calendar cl = Calendar.getInstance();
+		cl.setTime(datetime);
+		cl.add(Calendar.DATE, +day);
+		datetime = cl.getTime();
+		return datetime;
+	}
+
+	/**
+	 * 相加分钟
+	 *
+	 * @param datetime
+	 * @return
+	 */
+	public static Date dateFormatMINUTE(Date datetime, Integer day) {
+		Calendar cl = Calendar.getInstance();
+		cl.setTime(datetime);
+		cl.add(Calendar.MINUTE, +day);
+		datetime = cl.getTime();
+		return datetime;
+	}
+
+	/**
+	 * 根据小写数字格式的日期转换成大写格式的日期
+	 *
+	 * @param date
+	 * @return
+	 */
+	public final static char[] upper = "零一二三四五六七八九十".toCharArray();
+
+	public static String getUpperDate(String date) {
+		// 支持yyyy-MM-dd、yyyy/MM/dd、yyyyMMdd等格式
+		if (date == null)
+			return null;
+		// 非数字的都去掉
+		date = date.replaceAll("\\D", "");
+		if (date.length() != 8)
+			return null;
+		StringBuilder sb = new StringBuilder();
+		for (int i = 0; i < 4; i++) { // 年
+			sb.append(upper[Integer.parseInt(date.substring(i, i + 1))]);
+		}
+		sb.append("年"); // 拼接年
+		int month = Integer.parseInt(date.substring(4, 6));
+		if (month <= 10) {
+			sb.append(upper[month]);
+		} else {
+			sb.append("十").append(upper[month % 10]);
+		}
+		sb.append("月");// 拼接月
+
+		int day = Integer.parseInt(date.substring(6));
+		if (day <= 10) {
+			sb.append(upper[day]);
+		} else if (day < 20) {
+			sb.append("十").append(upper[day % 10]);
+		} else {
+			sb.append(upper[day / 10]).append("十");
+			int tmp = day % 10;
+			if (tmp != 0)
+				sb.append(upper[tmp]);
+		}
+		sb.append("日"); // 拼接日
+		return sb.toString();
+	}
+
+	/**
+	 * 相差天数
+	 *
+	 * @param startTime
+	 * @param endTime
+	 * @param format
+	 * @return
+	 */
+	public static Long dateDiff(String startTime, String endTime, String format) {
+		// 按照传入的格式生成一个simpledateformate对象
+		SimpleDateFormat sd = new SimpleDateFormat(format);
+		long nd = 1000 * 24 * 60 * 60;// 一天的毫秒数
+		// 获得两个时间的毫秒时间差异
+		Long diff;
+		try {
+			diff = sd.parse(endTime).getTime() - sd.parse(startTime).getTime();
+			long day = diff / nd;// 计算差多少天
+			return day;
+		} catch (ParseException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+
+			return null;
+		}
+	}
+	public static int daydiff(Date fDate, Date oDate) {
+
+		Calendar aCalendar = Calendar.getInstance();
+
+		aCalendar.setTime(fDate);
+
+		int day1 = aCalendar.get(Calendar.DAY_OF_YEAR);
+
+		aCalendar.setTime(oDate);
+
+		int day2 = aCalendar.get(Calendar.DAY_OF_YEAR);
+
+		return day2 - day1;
+
+	}
+
+
+
+	public static  Map<String, Object> getDays(Date date) {
+
+		String[] weekDays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
+		//创建日历类
+		Calendar calendar = Calendar.getInstance();
+		//获取当月月份
+		int month = calendar.get(Calendar.MONTH) + 1;
+		//设置当前月份
+		calendar.set(0, month, 0);
+		//获取当月每个月有多少天
+		int monthday = calendar.get(Calendar.DAY_OF_MONTH);
+		//设置当前时间
+		calendar.setTime(date);
+		//今天是几号
+		int today = calendar.get(Calendar.DATE);
+		//今天是周几
+		String weekday = weekDays[calendar.get(Calendar.DAY_OF_WEEK)-1];
+		Map<String,Object> map=new HashMap<>();
+		map.put("week",weekday);
+		map.put("day",today);
+		return map;
+	}
+
+	/**
+	 * 获取今天是几号
+	 * @return
+	 */
+	public static  Integer getDays() {
+		Integer dayOfMonth = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
+		return dayOfMonth;
+	}
+	/**
+	 * 获取某月的最后一天
+	 *
+	 */
+	public static String getLastDayOfMonth(int year,int month)
+	{
+		Calendar cal = Calendar.getInstance();
+		//设置年份
+		cal.set(Calendar.YEAR,year);
+		//设置月份
+		cal.set(Calendar.MONTH, month);
+		//获取当月最小值
+		int lastDay = cal.getMinimum(Calendar.DAY_OF_MONTH);
+		//设置日历中的月份,当月+1月-1天=当月最后一天
+		cal.set(Calendar.DAY_OF_MONTH, lastDay-1);
+		//格式化日期
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+		String lastDayOfMonth = sdf.format(cal.getTime());
+		return lastDayOfMonth;
+	}
+
+	public static void main(String[] args) {
+		Calendar calendar = Calendar.getInstance();
+		//获取当月月份
+		int month = calendar.get(Calendar.MONTH) + 2;
+		System.out.println(month);
+		System.out.println(getDays(new Date()));
+        System.out.println(getLastDayOfMonth(2023,3));
+	}
+
+}

+ 665 - 0
qnfhq-common/src/main/java/com/qnfhq/common/utils/StringUtils.java

@@ -0,0 +1,665 @@
+package com.qnfhq.common.utils;
+
+
+
+
+import cn.dev33.satoken.util.StrFormatter;
+import org.springframework.util.AntPathMatcher;
+
+import java.util.*;
+
+/**
+ * 字符串工具类
+ * 
+ * @author table
+ */
+public class StringUtils extends org.apache.commons.lang3.StringUtils
+{
+    /** 空字符串 */
+    private static final String NULLSTR = "";
+
+    /** 下划线 */
+    private static final char SEPARATOR = '_';
+
+    /** 星号 */
+    private static final char ASTERISK = '*';
+
+    /**
+     * 获取参数不为空值
+     * 
+     * @param value defaultValue 要判断的value
+     * @return value 返回值
+     */
+    public static <T> T nvl(T value, T defaultValue)
+    {
+        return value != null ? value : defaultValue;
+    }
+
+    /**
+     * * 判断一个Collection是否为空, 包含List,Set,Queue
+     * 
+     * @param coll 要判断的Collection
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Collection<?> coll)
+    {
+        return isNull(coll) || coll.isEmpty();
+    }
+
+    /**
+     * * 判断一个Collection是否非空,包含List,Set,Queue
+     * 
+     * @param coll 要判断的Collection
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Collection<?> coll)
+    {
+        return !isEmpty(coll);
+    }
+
+    /**
+     * * 判断一个对象数组是否为空
+     * 
+     * @param objects 要判断的对象数组
+     ** @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Object[] objects)
+    {
+        return isNull(objects) || (objects.length == 0);
+    }
+
+    /**
+     * * 判断一个对象数组是否非空
+     * 
+     * @param objects 要判断的对象数组
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Object[] objects)
+    {
+        return !isEmpty(objects);
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     * 
+     * @param map 要判断的Map
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Map<?, ?> map)
+    {
+        return isNull(map) || map.isEmpty();
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     * 
+     * @param map 要判断的Map
+     * @return true:非空 false:空
+     */
+    public static boolean isNotEmpty(Map<?, ?> map)
+    {
+        return !isEmpty(map);
+    }
+
+    /**
+     * * 判断一个字符串是否为空串
+     * 
+     * @param str String
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(String str)
+    {
+        return isNull(str) || NULLSTR.equals(str.trim());
+    }
+
+    /**
+     * * 判断一个字符串是否为非空串
+     * 
+     * @param str String
+     * @return true:非空串 false:空串
+     */
+    public static boolean isNotEmpty(String str)
+    {
+        return !isEmpty(str);
+    }
+
+    /**
+     * * 判断一个对象是否为空
+     * 
+     * @param object Object
+     * @return true:为空 false:非空
+     */
+    public static boolean isNull(Object object)
+    {
+        return object == null;
+    }
+
+    /**
+     * * 判断一个对象是否非空
+     * 
+     * @param object Object
+     * @return true:非空 false:空
+     */
+    public static boolean isNotNull(Object object)
+    {
+        return !isNull(object);
+    }
+
+    /**
+     * * 判断一个对象是否是数组类型(Java基本型别的数组)
+     * 
+     * @param object 对象
+     * @return true:是数组 false:不是数组
+     */
+    public static boolean isArray(Object object)
+    {
+        return isNotNull(object) && object.getClass().isArray();
+    }
+
+    /**
+     * 去空格
+     */
+    public static String trim(String str)
+    {
+        return (str == null ? "" : str.trim());
+    }
+
+    /**
+     * 替换指定字符串的指定区间内字符为"*"
+     *
+     * @param str 字符串
+     * @param startInclude 开始位置(包含)
+     * @param endExclude 结束位置(不包含)
+     * @return 替换后的字符串
+     */
+    public static String hide(CharSequence str, int startInclude, int endExclude)
+    {
+        if (isEmpty(str))
+        {
+            return NULLSTR;
+        }
+        final int strLength = str.length();
+        if (startInclude > strLength)
+        {
+            return NULLSTR;
+        }
+        if (endExclude > strLength)
+        {
+            endExclude = strLength;
+        }
+        if (startInclude > endExclude)
+        {
+            // 如果起始位置大于结束位置,不替换
+            return NULLSTR;
+        }
+        final char[] chars = new char[strLength];
+        for (int i = 0; i < strLength; i++)
+        {
+            if (i >= startInclude && i < endExclude)
+            {
+                chars[i] = ASTERISK;
+            }
+            else
+            {
+                chars[i] = str.charAt(i);
+            }
+        }
+        return new String(chars);
+    }
+
+    /**
+     * 截取字符串
+     * 
+     * @param str 字符串
+     * @param start 开始
+     * @return 结果
+     */
+    public static String substring(final String str, int start)
+    {
+        if (str == null)
+        {
+            return NULLSTR;
+        }
+
+        if (start < 0)
+        {
+            start = str.length() + start;
+        }
+
+        if (start < 0)
+        {
+            start = 0;
+        }
+        if (start > str.length())
+        {
+            return NULLSTR;
+        }
+
+        return str.substring(start);
+    }
+
+    /**
+     * 截取字符串
+     * 
+     * @param str 字符串
+     * @param start 开始
+     * @param end 结束
+     * @return 结果
+     */
+    public static String substring(final String str, int start, int end)
+    {
+        if (str == null)
+        {
+            return NULLSTR;
+        }
+
+        if (end < 0)
+        {
+            end = str.length() + end;
+        }
+        if (start < 0)
+        {
+            start = str.length() + start;
+        }
+
+        if (end > str.length())
+        {
+            end = str.length();
+        }
+
+        if (start > end)
+        {
+            return NULLSTR;
+        }
+
+        if (start < 0)
+        {
+            start = 0;
+        }
+        if (end < 0)
+        {
+            end = 0;
+        }
+
+        return str.substring(start, end);
+    }
+
+    /**
+     * 格式化文本, {} 表示占位符<br>
+     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
+     * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
+     * 例:<br>
+     * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     * 
+     * @param template 文本模板,被替换的部分用 {} 表示
+     * @param params 参数值
+     * @return 格式化后的文本
+     */
+    public static String format(String template, Object... params)
+    {
+        if (isEmpty(params) || isEmpty(template))
+        {
+            return template;
+        }
+        return StrFormatter.format(template, params);
+    }
+
+
+
+    /**
+     * 字符串转set
+     * 
+     * @param str 字符串
+     * @param sep 分隔符
+     * @return set集合
+     */
+    public static final Set<String> str2Set(String str, String sep)
+    {
+        return new HashSet<String>(str2List(str, sep, true, false));
+    }
+
+    /**
+     * 字符串转list
+     * 
+     * @param str 字符串
+     * @param sep 分隔符
+     * @param filterBlank 过滤纯空白
+     * @param trim 去掉首尾空白
+     * @return list集合
+     */
+    public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
+    {
+        List<String> list = new ArrayList<String>();
+        if (StringUtils.isEmpty(str))
+        {
+            return list;
+        }
+
+        // 过滤空白字符串
+        if (filterBlank && StringUtils.isBlank(str))
+        {
+            return list;
+        }
+        String[] split = str.split(sep);
+        for (String string : split)
+        {
+            if (filterBlank && StringUtils.isBlank(string))
+            {
+                continue;
+            }
+            if (trim)
+            {
+                string = string.trim();
+            }
+            list.add(string);
+        }
+
+        return list;
+    }
+
+    /**
+     * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
+     *
+     * @param collection 给定的集合
+     * @param array 给定的数组
+     * @return boolean 结果
+     */
+    public static boolean containsAny(Collection<String> collection, String... array)
+    {
+        if (isEmpty(collection) || isEmpty(array))
+        {
+            return false;
+        }
+        else
+        {
+            for (String str : array)
+            {
+                if (collection.contains(str))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
+     *
+     * @param cs 指定字符串
+     * @param searchCharSequences 需要检查的字符串数组
+     * @return 是否包含任意一个字符串
+     */
+    public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
+    {
+        if (isEmpty(cs) || isEmpty(searchCharSequences))
+        {
+            return false;
+        }
+        for (CharSequence testStr : searchCharSequences)
+        {
+            if (containsIgnoreCase(cs, testStr))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 驼峰转下划线命名
+     */
+    public static String toUnderScoreCase(String str)
+    {
+        if (str == null)
+        {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        // 前置字符是否大写
+        boolean preCharIsUpperCase = true;
+        // 当前字符是否大写
+        boolean curreCharIsUpperCase = true;
+        // 下一字符是否大写
+        boolean nexteCharIsUpperCase = true;
+        for (int i = 0; i < str.length(); i++)
+        {
+            char c = str.charAt(i);
+            if (i > 0)
+            {
+                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
+            }
+            else
+            {
+                preCharIsUpperCase = false;
+            }
+
+            curreCharIsUpperCase = Character.isUpperCase(c);
+
+            if (i < (str.length() - 1))
+            {
+                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
+            }
+
+            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
+            {
+                sb.append(SEPARATOR);
+            }
+            else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
+            {
+                sb.append(SEPARATOR);
+            }
+            sb.append(Character.toLowerCase(c));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 是否包含字符串
+     * 
+     * @param str 验证字符串
+     * @param strs 字符串组
+     * @return 包含返回true
+     */
+    public static boolean inStringIgnoreCase(String str, String... strs)
+    {
+        if (str != null && strs != null)
+        {
+            for (String s : strs)
+            {
+                if (str.equalsIgnoreCase(trim(s)))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 删除最后一个字符串
+     *
+     * @param str 输入字符串
+     * @param spit 以什么类型结尾的
+     * @return 截取后的字符串
+     */
+    public static String lastStringDel(String str, String spit)
+    {
+        if (!StringUtils.isEmpty(str) && str.endsWith(spit))
+        {
+            return str.subSequence(0, str.length() - 1).toString();
+        }
+        return str;
+    }
+
+    /**
+     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
+     * 
+     * @param name 转换前的下划线大写方式命名的字符串
+     * @return 转换后的驼峰式命名的字符串
+     */
+    public static String convertToCamelCase(String name)
+    {
+        StringBuilder result = new StringBuilder();
+        // 快速检查
+        if (name == null || name.isEmpty())
+        {
+            // 没必要转换
+            return "";
+        }
+        else if (!name.contains("_"))
+        {
+            // 不含下划线,仅将首字母大写
+            return name.substring(0, 1).toUpperCase() + name.substring(1);
+        }
+        // 用下划线将原始字符串分割
+        String[] camels = name.split("_");
+        for (String camel : camels)
+        {
+            // 跳过原始字符串中开头、结尾的下换线或双重下划线
+            if (camel.isEmpty())
+            {
+                continue;
+            }
+            // 首字母大写
+            result.append(camel.substring(0, 1).toUpperCase());
+            result.append(camel.substring(1).toLowerCase());
+        }
+        return result.toString();
+    }
+
+    /**
+     * 驼峰式命名法
+     * 例如:user_name->userName
+     */
+    public static String toCamelCase(String s)
+    {
+        if (s == null)
+        {
+            return null;
+        }
+        if (s.indexOf(SEPARATOR) == -1)
+        {
+            return s;
+        }
+        s = s.toLowerCase();
+        StringBuilder sb = new StringBuilder(s.length());
+        boolean upperCase = false;
+        for (int i = 0; i < s.length(); i++)
+        {
+            char c = s.charAt(i);
+
+            if (c == SEPARATOR)
+            {
+                upperCase = true;
+            }
+            else if (upperCase)
+            {
+                sb.append(Character.toUpperCase(c));
+                upperCase = false;
+            }
+            else
+            {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
+     * 
+     * @param str 指定字符串
+     * @param strs 需要检查的字符串数组
+     * @return 是否匹配
+     */
+    public static boolean matches(String str, List<String> strs)
+    {
+        if (isEmpty(str) || isEmpty(strs))
+        {
+            return false;
+        }
+        for (String pattern : strs)
+        {
+            if (isMatch(pattern, str))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断url是否与规则配置: 
+     * ? 表示单个字符; 
+     * * 表示一层路径内的任意字符串,不可跨层级; 
+     * ** 表示任意层路径;
+     * 
+     * @param pattern 匹配规则
+     * @param url 需要匹配的url
+     * @return
+     */
+    public static boolean isMatch(String pattern, String url)
+    {
+        AntPathMatcher matcher = new AntPathMatcher();
+        return matcher.match(pattern, url);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T cast(Object obj)
+    {
+        return (T) obj;
+    }
+
+    /**
+     * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
+     * 
+     * @param num 数字对象
+     * @param size 字符串指定长度
+     * @return 返回数字的字符串格式,该字符串为指定长度。
+     */
+    public static final String padl(final Number num, final int size)
+    {
+        return padl(num.toString(), size, '0');
+    }
+
+    /**
+     * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
+     * 
+     * @param s 原始字符串
+     * @param size 字符串指定长度
+     * @param c 用于补齐的字符
+     * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
+     */
+    public static final String padl(final String s, final int size, final char c)
+    {
+        final StringBuilder sb = new StringBuilder(size);
+        if (s != null)
+        {
+            final int len = s.length();
+            if (s.length() <= size)
+            {
+                for (int i = size - len; i > 0; i--)
+                {
+                    sb.append(c);
+                }
+                sb.append(s);
+            }
+            else
+            {
+                return s.substring(len - size, len);
+            }
+        }
+        else
+        {
+            for (int i = size; i > 0; i--)
+            {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+}