租赁系统

This commit is contained in:
yyb
2026-01-05 15:46:59 +08:00
parent 61fa33c27c
commit 5559163b2e
385 changed files with 33178 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseMachineConfig;
/**
* <p>
* GPU对应币种挖矿算力(只要gpu类型相同那么就使用这个配置) 服务类
* </p>
*
* @author yyb
* @since 2025-11-27
*/
public interface LeaseMachineConfigService extends IService<LeaseMachineConfig> {
}

View File

@@ -0,0 +1,16 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseMachinePrice;
/**
* <p>
* 商品表对应的物品机器表 服务类
* </p>
*
* @author yyb
* @since 2025-11-25
*/
public interface LeaseMachinePriceService extends IService<LeaseMachinePrice> {
}

View File

@@ -0,0 +1,95 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.PageResult;
import com.m2pool.lease.dto.Result;
import com.m2pool.lease.dto.v2.MachineInfoDto;
import com.m2pool.lease.dto.v2.SellerMachineInfoDto;
import com.m2pool.lease.dto.v2.ShopInfoDto;
import com.m2pool.lease.entity.LeaseMachine;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.ProductPageVo;
import com.m2pool.lease.vo.v2.*;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
* <p>
* gpu类型出售矿机表 服务类
* </p>
*
* @author yyb
* @since 2025-11-21
*/
public interface LeaseMachineService extends IService<LeaseMachine> {
/**
* 获取商品对应的实际商品列表
* @return
*/
PageResult<ShopInfoDto> getShopList(ProductPageVo productPageVo);
/**
* 获取店铺矿机详情
* @return
*/
PageResult<MachineInfoDto> getShopMachineList(ShopMachineVo shopMachineVo);
/**
* 获取卖家页面矿机列表
* @return
*/
PageResult<SellerMachineInfoDto> getShopMachineListForSeller(SellerMachineVo sellerMachineVo);
/**
* 添加ASIC矿机
* @return
*/
Result<String> addAsicMachine( AsicMachineParamsVo asicMachineParamsVo);
/**
* 修改ASIC矿机
* @return
*/
Result<String> updateAsicMachine( AsicMachineParamsVo asicMachineParamsVo);
/**
* 修改GPU矿机
* @return
*/
Result<String> updateGpuMachine(List<GpuMachineParamsVo> gpuMachineParamsVoList);
/**
* 矿机上下架
* @return
*/
Result<String> updateMachineState(MachineStateVo machineStateVo);
/**
* 删除矿机
* @return
*/
Result<String> deleteMachine(BaseVo baseVo);
/**
* 获取支持的币种
* @return
*/
Result<List<String>> getSupportCoin();
/**
* 获取支持的算法
* @return
*/
Result<List<String>> getSupportAlgo( String coin);
}

View File

@@ -0,0 +1,16 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseNexaMachineAvgPower;
/**
* <p>
* 矿池nexa机器实时平均算力 服务类
* </p>
*
* @author yyb
* @since 2025-07-29
*/
public interface LeaseNexaMachineAvgPowerService extends IService<LeaseNexaMachineAvgPower> {
}

View File

@@ -0,0 +1,16 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseNexaMachinePower;
/**
* <p>
* 已售商品矿工实时算力表 服务类
* </p>
*
* @author yyb
* @since 2025-07-25
*/
public interface LeaseNexaMachinePowerService extends IService<LeaseNexaMachinePower> {
}

View File

@@ -0,0 +1,107 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.dto.v2.*;
import com.m2pool.lease.entity.LeaseOrderInfo;
import com.m2pool.lease.vo.*;
import com.m2pool.lease.vo.v2.CoinAndAlgorithmVo;
import java.math.BigDecimal;
import java.util.List;
/**
* <p>
* 订单表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseOrderInfoService extends IService<LeaseOrderInfo> {
/**
* 添加订单
* @param orderAndCodeVo
* @return
*/
Result<String> addOrders(OrderAndCodeVo orderAndCodeVo);
/**
* 再次购买
* @param orderInfoVoList
* @return
*/
Result<List<PaymentRecordDto>> buyAgain(List<OrderInfoVo> orderInfoVoList);
/**
* 根据订单状态查询订单列表(买家)
* @param orderInfoStateVo
* @return
*/
PageResult<OrderInfoDto> getOrdersByStatus(OrderInfoStateVo orderInfoStateVo);
/**
* 根据订单状态查询订单列表(卖家)
* @param orderInfoStateVo
* @return
*/
PageResult<OrderInfoDto> getOrdersByStatusForSeller(OrderInfoStateVo orderInfoStateVo);
/**
* 根据订单id查询订单
* @param orderVo
* @return
*/
Result<OrderInfoDto> getOrdersByIds( OrderVo orderVo);
/**
* 取消订单
* @param orderVo
* @return
*/
Result<String> cancelOrder(OrderVo orderVo);
/**
* 获取用户选择的支付币种 获取实时币价
* @param coinVo
* @return
*/
Result<BigDecimal> getCoinPrice(CoinVo coinVo);
/**
* 获取矿机对应的支持币种和算法
* @return
*/
Result<List<CoinAndAlgorithmListDto>> getMachineSupportCoinAndAlgorithm(List<BaseVo> machineIds);
/**
* 获取当前矿机支持的矿池币种信息
* @param machineIds
* @return
*/
Result<List<MiningInfoDto>> getMachineSupportPool(CoinAndAlgorithmVo coinAndAlgorithmVo);
/**
* 添加订单-V2
* @param orderAndCodeVo
* @return
*/
Result<String> addOrdersV2( OrderAndCodeVo orderAndCodeVo);
/**
* 获取用户已购商品列表-V2
* @param pageVo
* @return
*/
PageResult<PurchasedMachineListDto> getPurchasedItems(PageVo pageVo);
/**
* 根据id查询用户已购商品详情-V2
* @param baseVo
* @return
*/
Result<MiningConfigInfoDto> getPurchasedInfo(BaseVo baseVo);
}

View File

@@ -0,0 +1,16 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseOrderItem;
/**
* <p>
* 订单明细表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseOrderItemService extends IService<LeaseOrderItem> {
}

View File

@@ -0,0 +1,16 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeasePayRecordMessage;
import com.m2pool.lease.entity.LeasePayRecordMessageInfo;
/**
* <p>
* service层支付
* </p>
*
* @author yyb
* @since 2025-09-10
*/
public interface LeasePayRecordMessageInfoService extends IService<LeasePayRecordMessageInfo> {
}

View File

@@ -0,0 +1,15 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeasePayRecordMessage;
/**
* <p>
* service层支付
* </p>
*
* @author yyb
* @since 2025-09-10
*/
public interface LeasePayRecordMessageService extends IService<LeasePayRecordMessage> {
}

View File

@@ -0,0 +1,66 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.PaymentCallbackDto;
import com.m2pool.lease.dto.PaymentRecordDto;
import com.m2pool.lease.dto.Result;
import com.m2pool.lease.entity.LeasePaymentRecord;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.CheckPayStatusVo;
import com.m2pool.lease.vo.OrderVo;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
import java.util.Map;
/**
* <p>
* 支付记录表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeasePaymentRecordService extends IService<LeasePaymentRecord> {
/**
* 创建支付订单
*
* @param orderVo
* @return
*/
Result<List<PaymentRecordDto>> addPayOrder(OrderVo orderVo);
/**
* 根据订单id查询支付订单
*
* @param orderVo
* @return
*/
Result<List<PaymentRecordDto>> getPayOrderByOrderId( OrderVo orderVo);
/**
* 支付回调结果---校验支付是否成功(批量校验)
*
* @param checkPayStatusVoList
* @return
*/
Result<List<PaymentCallbackDto>> paymentCallbackBatch(List<CheckPayStatusVo> checkPayStatusVoList);
/**
* 支付回调结果----根据支付订单id校验支付是否成功(单个校验)
* @param checkPayStatusVo
* @return
*/
Result<PaymentCallbackDto> paymentCallbackByPayId(CheckPayStatusVo checkPayStatusVo);
/**
* 支付回调结果-----用于定时任务
* @param leasePaymentRecordList
* @return
*/
void paymentCallbackTask(List<LeasePaymentRecord> leasePaymentRecordList);
}

View File

@@ -0,0 +1,16 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseProductIncome;
/**
* <p>
* 商品收益表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseProductIncomeService extends IService<LeaseProductIncome> {
}

View File

@@ -0,0 +1,17 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseProductMachinePrice;
/**
* <p>
* 商品表对应的物品机器表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseProductMachinePriceService extends IService<LeaseProductMachinePrice> {
}

View File

@@ -0,0 +1,77 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.PageResult;
import com.m2pool.lease.dto.ProductUpdateMachineDto;
import com.m2pool.lease.dto.Result;
import com.m2pool.lease.dto.UserMinerDto;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.vo.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* <p>
* 商品表对应的物品机器表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseProductMachineService extends IService<LeaseProductMachine> {
/**
* 获取当前账户对应的挖矿账户
* @return
*/
Result<Map<String, List<UserMinerDto>>> getUserMinersList(UserMinerVo userMinerVo);
/**
* 获取当前账户对应的挖矿账户的机器矿工集合
* @param userMinerVo
* @return
*/
Result<List<UserMinerDto>> getUserMachineList(UserMinerVo userMinerVo);
/**
* 根据商品id查询商品矿机列表---用于卖方修改矿机信息
* @param productForUpdateMachineVo
* @return
*/
PageResult<ProductUpdateMachineDto> getMachineListForUpdate(ProductForUpdateMachineVo productForUpdateMachineVo);
/**
* 新增商品库存---实际需出售机器
* @param productMachineParamsVoList
* @return
*/
Result<String> addSingleOrBatchMachine(ProductMachineParamsVo productMachineParamsVoList);
/**
* 编辑商品 + 商品上下架---实际需出售机器
* @param productUpdateMachineVoList
* @return
*/
Result<String> updateMachine(List<ProductUpdateMachineVo> productUpdateMachineVoList);
/**
* 删除商品---实际需出售机器
* @param baseVo
* @return
*/
Result<String> deleteMachine(BaseVo baseVo);
/**
* 计算价格
* @param priceCalculateVo
* @return
*/
Result<BigDecimal> calculatePrice(PriceCalculateVo priceCalculateVo);
}

View File

@@ -0,0 +1,93 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.LeaseProduct;
import com.m2pool.lease.vo.*;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* <p>
* 商品表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseProductService extends IService<LeaseProduct> {
/**
* 查询商品列表
*
* @return Result<List<ProductDto>> 封装后的商品 DTO 列表
*/
PageResult<ProductDto> getProductList(ProductPageVo productPageVo);
/**
* 根据商品 ID 查询商品详情
*
* @param BaseVo 商品 ID
* @return Result<ProductDto> 封装后的商品 DTO
*/
Result<ProductDto> getMachineInfoById( BaseVo baseVo);
/**
* 根据商品 ID 查询商品详情
*
* @param productId 商品 ID
* @return Result<ProductDto> 封装后的商品 DTO
*/
PageResult<ProductMachineDto> getProductMachineInfo(ProductMachineVo productMachineVo);
/**
* 单个商品矿机列表页面---获取支付方式
* @return
*/
Result<List<PayConfigDto>> getPayTypes(ShopPayTypeVo shopPayTypeVo);
/**
* 新增商品
*
* @param productURDVo 商品 DTO
* @return Result<Boolean> 操作结果
*/
Result<String> addProduct(ProductURDVo productURDVo);
/**
* 编辑商品
*
* @param productURDVo 商品 DTO
* @return Result<Boolean> 操作结果
*/
Result<String> updateProduct(ProductURDVo productURDVo);
/**
* 删除商品
* @param id
* @return
*/
Result<String> deleteProduct(Long id);
/**
* 查询用户店铺支持的支付方式
* @return
*/
Result<List<PayTypeDto>> getSupportPayType();
/**
* 获取商品列表用于店铺钱包配置
* @return
*/
Result<List<ProductForWalletConfigDto>> getProductListForShopWalletConfig();
/**
* 修改商品列表用于店铺钱包配置
* @return
*/
Result<String> updateProductListForShopWalletConfig(ProductMachineForWalletConfigVo productMachineForWalletConfigVo);
}

View File

@@ -0,0 +1,16 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseShopConfig;
/**
* <p>
* 店铺商品配置表 服务类
* </p>
*
* @author yyb
* @since 2025-08-05
*/
public interface LeaseShopConfigService extends IService<LeaseShopConfig> {
}

View File

@@ -0,0 +1,146 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.dto.v2.PayWithdrawSellerRecordDto;
import com.m2pool.lease.dto.v2.ShopWalletInfoDto;
import com.m2pool.lease.entity.LeaseShop;
import com.m2pool.lease.vo.*;
import com.m2pool.lease.vo.v2.ShopWalletInfoVo;
import java.util.List;
/**
* <p>
* 店铺表 服务类
* </p>
*
* @author yyb
* @since 2025-08-05
*/
public interface LeaseShopService extends IService<LeaseShop> {
/**
* 新增店铺
* @param shopVo
* @return
*/
Result<String> addShop(ShopVo shopVo);
/**
* 修改店铺
* @param shopVo
* @return
*/
Result<String> updateShop( ShopVo shopVo);
/**
* 关闭店铺
* @param baseVo
* @return
*/
Result<String> closeShop( BaseVo baseVo);
/**
* 根据用户邮箱查询店铺
* @return
*/
Result<ShopDto> getShopByUserEmail();
/**
* 根据店铺id查询店铺
* @param baseVo
* @return
*/
Result<ShopDto> getShopById(BaseVo baseVo);
/**
* 删除店铺
* @param baseVo
* @return
*/
Result<String> deleteShop(BaseVo baseVo);
/**
* 根据店铺id 获取店铺配置信息列表
* @param baseVo
* @return
*/
Result<List<ShopConfigDto>> getShopConfig(BaseVo baseVo);
/**
* 根据 店铺id 获取店铺商品列表
* @param baseVo
* @return
*/
Result<List<ShopNameDto>> getProductListById(BaseVo baseVo);
/**
* 新增商铺配置
* @param shopConfigVo
* @return
*/
Result<String> addShopConfig( ShopConfigVo shopConfigVo);
/**
* 修改商铺配置
* @param shopConfigVo
* @return
*/
Result<String> updateShopConfig( ShopConfigVo shopConfigVo);
/**
* 删除商铺配置
* @param baseVo
* @return
*/
Result<String> deleteShopConfig(BaseVo baseVo);
/**
* 获取链和链列表
* @return
*/
Result<List<ChainListDto>> getChainAndList();
Result<List<ChainListDto>> getChainAndListForSeller( BaseVo baseVo);
Result<ChainListDto> getChainAndCoin(BaseVo baseVo);
/**
* 根据店铺id 获取店铺配置信息列表--v2 新增手续费和钱包余额
* @param baseVo
* @return
*/
Result<List<ShopWalletInfoDto>> getShopConfigV2(BaseVo baseVo);
/**
* 卖家余额提现
* @param balanceVo
* @return
*/
Result<String> withdrawBalanceForSeller(BalanceVo balanceVo);
/**
* 修改商铺配置--v2 新增手续费和钱包余额
*/
Result<String> updateShopConfigV2(ShopWalletInfoVo shopWalletInfoVo);
/**
* 获取店铺内所有钱包(包含历史钱包)提现列表
* @return
*/
PageResult<PayWithdrawSellerRecordDto> balanceWithdrawList(PageVo pageVo);
}

View File

@@ -0,0 +1,17 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.entity.LeaseShoppingCartInfo;
/**
* <p>
* 购物车详情表 服务类
* </p>
*
* @author yyb
* @since 2025-07-24
*/
public interface LeaseShoppingCartInfoService extends IService<LeaseShoppingCartInfo> {
}

View File

@@ -0,0 +1,90 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.PageResult;
import com.m2pool.lease.dto.Result;
import com.m2pool.lease.dto.ShopCartDto;
import com.m2pool.lease.dto.v2.ShopCartV2Dto;
import com.m2pool.lease.entity.LeaseShoppingCart;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.PageVo;
import com.m2pool.lease.vo.ProductAndMachineVo;
import com.m2pool.lease.vo.ShoppingCartInfoURDVo;
import com.m2pool.lease.vo.v2.AddGoodsVo;
import com.m2pool.lease.vo.v2.CartInfoVo;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* <p>
* 购物车表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseShoppingCartService extends IService<LeaseShoppingCart> {
/**
* 添加购物车
* @param shoppingCartInfoURDVoList
* @return
*/
Result<String> addGoods(List<ShoppingCartInfoURDVo> shoppingCartInfoURDVoList);
/**
* 获取购物车列表
* @param pageVo
* @return
*/
PageResult<ShopCartDto> getGoodsList(PageVo pageVo);
/**
* 批量删除购物车
* @param baseVoList
* @return
*/
Result<String> deleteBatchGoods(List<ProductAndMachineVo> baseVoList);
/**
* 删除购物车
* @param baseVo
* @return
*/
Result<String> deleteGoods(BaseVo baseVo);
/**
* 批量删除购物车中已下架商品
* @return
*/
Result<String> deleteBatchGoodsForIsDelete();
/**
* 批量添加购物车
* @param addGoodsVoList
* @return
*/
Result<String> addGoodsV2(List<AddGoodsVo> addGoodsVoList);
/**
* 查询购物车中商品列表
* @param pageVo
* @return
*/
PageResult<ShopCartV2Dto> getGoodsListV2(PageVo pageVo);
/**
* 批量删除购物车中商品
* @param baseVoList
* @return
*/
Result<String> deleteBatchGoodsV2(List<CartInfoVo> baseVoList);
/**
* 批量删除购物车中已下架商品
* @return
*/
Result<String> deleteBatchGoodsForIsDeleteV2();
}

View File

@@ -0,0 +1,49 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.PageResult;
import com.m2pool.lease.dto.Result;
import com.m2pool.lease.dto.UserOwnedProductDto;
import com.m2pool.lease.entity.LeaseOrderItem;
import com.m2pool.lease.entity.LeasePaymentRecord;
import com.m2pool.lease.entity.LeaseUserOwnedProduct;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.UserOwnedProductVo;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* <p>
* 用户拥有商品详情表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseUserOwnedProductService extends IService<LeaseUserOwnedProduct> {
/**
* 用户查询当前自身已购商品列表
*
* @param userOwnedProductVo
* @return
*/
PageResult<UserOwnedProductDto> getOwnedList(UserOwnedProductVo userOwnedProductVo);
/**
* 根据id查询当前自身已购商品详情
*
* @param baseVo
* @return
*/
Result<UserOwnedProductDto> getOwnedById(BaseVo baseVo);
/**
* 支付验证成功后去修改订单等信息
* @param leaseOrderItems
* @return
*/
boolean afterPaySuccessTodoSomeEvent(List<LeaseOrderItem> leaseOrderItems);
}

View File

@@ -0,0 +1,245 @@
package com.m2pool.lease.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.dto.v2.GoogleInfoDto;
import com.m2pool.lease.entity.LeaseUser;
import com.m2pool.lease.vo.*;
import com.m2pool.lease.vo.v2.CloseAccountVo;
import com.m2pool.lease.vo.v2.GoogleBindVo;
import com.m2pool.lease.vo.v2.GoogleCloseVo;
import org.springframework.web.bind.annotation.RequestBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
/**
* <p>
* 用户表 服务类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
public interface LeaseUserService extends IService<LeaseUser> {
/*---------------用户权限-----------------------*/
/**
* 用户登录/注册
* @param userLoginVo
* @return
*/
Result<Map<String, Object>> login(UserLoginVo userLoginVo);
/**
* 用户注册
* @param userRegisterVo
* @return
*/
Result<String> register( UserRegisterVo userRegisterVo);
/**
* 登录页面----忘记密码:重置密码
* @param userLoginVo
* @return
*/
Result<String> updatePassword(UserLoginVo userLoginVo);
/**
* 个人中心--修改密码
* @param restPwdVo
* @return
*/
Result<String> updatePasswordInCenter(RestPwdVo restPwdVo);
/**
* 发送用户登录邮箱验证码
* @param emailCodeVo
* @return
*/
Result<String> sendLoginCode( EmailCodeVo emailCodeVo);
/**
* 获取用户注册邮箱验证码
* @param emailCodeVo
* @return
*/
Result<String> sendRegisterCode(EmailCodeVo emailCodeVo);
/**
* 获取用户修改密码邮箱验证码
* @param emailCodeVo
* @return
*/
Result<String> sendUpdatePwdCode(EmailCodeVo emailCodeVo);
/**
* 登出
* @return
*/
Result<String> logout();
/**
* 用户注销
* @param closeAccountVo
* @return
*/
Result<String> closeAccount(CloseAccountVo closeAccountVo);
/**
* 发送用户注销邮箱验证码
* @param emailCodeVo
* @return
*/
Result<String> sendCloseAccount( EmailCodeVo emailCodeVo);
/*---------------用户权限-----------------------*/
/*---------------谷歌双重验证-----------------------*/
/**
* 绑定谷歌验证码
* @param googleBindVo
* @return
*/
Result<String> bindGoogle( GoogleBindVo googleBindVo);
/**
* 获取谷歌验证器安全码和验证码
* @return
*/
Result<GoogleInfoDto> getBindInfo();
/**
* 发送谷歌验证器邮箱验证码
* @return
*/
Result<String> sendOpenGoogleCode();
/**
* 发送关闭谷歌验证 邮箱验证码
* @return
*/
Result<String> sendCloseGoogleCode();
/**
* 关闭双重验证
* @param vo
* @return
*/
Result<String> closeStepTwo(GoogleCloseVo vo);
/**
* 获取谷歌验证器状态
* @return
*/
Result<Integer> getGoogleStatus();
/**
* 开启双重验证
* @param vo
* @return
*/
Result<String> openStepTwo(GoogleCloseVo vo);
/*---------------谷歌双重验证-----------------------*/
/*---------------用户信息-----------------------*/
/**
* 绑定钱包
* @param chainAndCoinVo
* @return
*/
Result<UserWalletDataDto> bindWallet( ChainAndCoinVo chainAndCoinVo);
/**
* 获取用户相关钱包信息
* @return
*/
Result<List<UserWalletDataDto>> getWalletInfo();
/**
* 余额提现
* @return
*/
Result<String> withdrawBalance(BalanceVo balanceVo);
/**
* 获取余额提现记录列表
* @param balancePageVo
* @return
*/
PageResult<PayWithdrawMessageDto> balanceWithdrawList(BalancePageVo balancePageVo);
/**
* 获取余额充值记录列表
* @param balancePageVo
* @return
*/
PageResult<PayRechargeMessageDto> balanceRechargeList(BalancePageVo balancePageVo);
/**
* 卖家:获取钱包交易(收款)记录表
* @param balancePageVo
* @return
*/
PageResult<PayRecordMessageDto> balancePayList(BalancePageVo balancePageVo);
/**
* 卖家:获取钱包交易(收款)记录表
* @param recordTypePageVo
* @return
*/
PageResult<TransactionRecordDto> transactionRecord( RecordTypePageVo recordTypePageVo);
/**
* 最近5条交易
* @return
*/
Result<List<RecentlyTransactionDto>> getRecentlyTransaction();
/**
* 获取手续费
* @return
*/
Result<List<ChargeDto>> getCharge();
/**
* 下载客户端
* @param response
* @return
*/
void downloadClient(String userEmail,String type,HttpServletRequest request, HttpServletResponse response);
/**
* 获取用户信息
* @return
*/
String getClientVersion();
/*---------------用户信息-----------------------*/
}

View File

@@ -0,0 +1,20 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseMachineConfig;
import com.m2pool.lease.mapper.LeaseMachineConfigMapper;
import com.m2pool.lease.service.LeaseMachineConfigService;
import org.springframework.stereotype.Service;
/**
* <p>
* GPU对应币种挖矿算力(只要gpu类型相同那么就使用这个配置) 服务实现类
* </p>
*
* @author yyb
* @since 2025-11-27
*/
@Service
public class LeaseMachineConfigServiceImpl extends ServiceImpl<LeaseMachineConfigMapper, LeaseMachineConfig> implements LeaseMachineConfigService {
}

View File

@@ -0,0 +1,20 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseMachinePrice;
import com.m2pool.lease.mapper.LeaseMachinePriceMapper;
import com.m2pool.lease.service.LeaseMachinePriceService;
import org.springframework.stereotype.Service;
/**
* <p>
* 商品表对应的物品机器表 服务实现类
* </p>
*
* @author yyb
* @since 2025-11-25
*/
@Service
public class LeaseMachinePriceServiceImpl extends ServiceImpl<LeaseMachinePriceMapper, LeaseMachinePrice> implements LeaseMachinePriceService {
}

View File

@@ -0,0 +1,470 @@
package com.m2pool.lease.service.impl;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.dto.v2.*;
import com.m2pool.lease.entity.LeaseMachine;
import com.m2pool.lease.entity.LeaseMachineConfig;
import com.m2pool.lease.entity.LeaseMachinePrice;
import com.m2pool.lease.entity.LeaseShop;
import com.m2pool.lease.exception.MachineException;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.service.LeaseMachineConfigService;
import com.m2pool.lease.service.LeaseMachinePriceService;
import com.m2pool.lease.service.LeaseMachineService;
import com.m2pool.lease.utils.SecurityUtils;
import com.m2pool.lease.utils.UuidGeneratorUtil;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.ProductPageVo;
import com.m2pool.lease.vo.v2.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
* gpu类型出售矿机表 服务实现类
* </p>
*
* @author yyb
* @since 2025-11-21
*/
@Service
public class LeaseMachineServiceImpl extends ServiceImpl<LeaseMachineMapper, LeaseMachine> implements LeaseMachineService {
@Resource
private LeaseShopConfigMapper leaseShopConfigMapper;
@Resource
private LeaseMachineMapper leaseMachineMapper;
@Resource
private LeaseShopMapper leaseShopMapper;
@Resource
private LeaseMachineConfigMapper leaseMachineConfigMapper;
@Resource
private LeaseMachinePriceMapper leaseMachinePriceMapper;
@Resource
private LeaseMachineConfigService leaseMachineConfigService;
@Resource
private LeaseMachinePriceService leaseMachinePriceService;
public LeaseShop getShopById() {
return leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>().eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
.eq(LeaseShop::getDel, false));
}
@Override
public PageResult<ShopInfoDto> getShopList(ProductPageVo productPageVo) {
//获取到矿机
Set<Long> shopIds = leaseMachineMapper.getShopIds();
if (shopIds.isEmpty()){
//未查询到店铺
return PageResult.success(new ArrayList<>());
}
PageHelper.startPage(productPageVo.getPageNum(), productPageVo.getPageSize());
List<ShopInfoDto> existsMachineShop = leaseMachineMapper.getExistsMachineShop(shopIds, productPageVo.getCoin(), productPageVo.getAlgorithm());
PageInfo<ShopInfoDto> pageInfo = new PageInfo<>(existsMachineShop);
//店铺支付方式
List<PayTypeDto> payType = leaseShopConfigMapper.getPayType(new ArrayList<>(shopIds));
Map<Long, List<PayTypeDto>> payTypeMap = payType.stream().collect(Collectors.groupingBy(PayTypeDto::getShopId));
PageResult<ShopInfoDto> success = PageResult.success(existsMachineShop);
for (ShopInfoDto shopInfoDto : success.getRows()) {
shopInfoDto.setPayTypes(payTypeMap.get(shopInfoDto.getShopId()));
}
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
@Override
public PageResult<MachineInfoDto> getShopMachineList(ShopMachineVo shopMachineVo) {
//获取店铺钱包信息
List<PayConfigDto> shopWalletInfo = leaseShopMapper.getShopWalletInfo(shopMachineVo.getShopId());
//分页查询矿机基础信息
PageHelper.startPage(shopMachineVo.getPageNum(), shopMachineVo.getPageSize());
shopMachineVo = buildQuery(shopMachineVo,shopWalletInfo.get(0));
List<MachineInfoDto> machineInfoDtoList = leaseMachineMapper.getShopMachineList(shopMachineVo);
PageInfo<MachineInfoDto> pageInfo = new PageInfo<>(machineInfoDtoList);
//获取gpu和asic对应币种算力和月收益信息
PageResult<MachineInfoDto> success = setGpuAndAsicInfo(PageResult.successColumns(machineInfoDtoList),shopMachineVo);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
/**
* 设置gpu和asic 对应的收益列表信息
* @param
*/
public PageResult<MachineInfoDto> setGpuAndAsicInfo(PageResult<MachineInfoDto> success,ShopMachineVo shopMachineVo) {
List<MachineInfoDto> machineInfoDtoList = success.getRows();
List<TableHeadersDto> columns = success.getColumns();
if (!machineInfoDtoList.isEmpty()){
List<Long> machineIds = machineInfoDtoList.stream()
.map(MachineInfoDto::getId).collect(Collectors.toList());
//获取价格列表(价格列表只与主表有关与machine_config 表无关)
List<MachinePayTypeDto> machinePriceByMachineIds = leaseMachinePriceMapper.getMachinePriceByMachineIds(machineIds);
Map<Long, List<MachinePayTypeDto>> machinePriceMap = machinePriceByMachineIds.stream()
.collect(Collectors.groupingBy(MachinePayTypeDto::getProductMachineId));
//动态列:获取每个矿机前十个币种算法的配置
List<PowerIncomeInfoDto> gpuConfigList = leaseMachineMapper.getGpuConfigList(machineIds);
Map<Long, List<PowerIncomeInfoDto>> collect = gpuConfigList.stream()
.collect(Collectors.groupingBy(PowerIncomeInfoDto::getMachineId));
for (MachineInfoDto machineInfo : machineInfoDtoList) {
machineInfo.setPriceList(machinePriceMap.get(machineInfo.getId()));
List<PowerIncomeInfoDto> powerIncomeInfoDtoList = collect.get(machineInfo.getId());
for (int i = 0; i < powerIncomeInfoDtoList.size(); i++) {
PowerIncomeInfoDto powerIncomeInfoDto = powerIncomeInfoDtoList.get(i);
setDynamicColumn(columns,powerIncomeInfoDto,machineInfo);
}
}
//排序分页后对象
List<MachineInfoDto> sorted = sorted(machineInfoDtoList, shopMachineVo);
success.setRows(sorted);
success.setColumns(columns);
}
return success;
}
/**
* 设置算力动态列
* @param columns
*/
public void setDynamicColumn(List<TableHeadersDto> columns,PowerIncomeInfoDto powerIncomeInfoDto,MachineInfoDto machineInfo){
TableHeadersDto column = TableHeadersDto.builder()
.label(powerIncomeInfoDto.getCoin())
.type("hashrate")
.unit(powerIncomeInfoDto.getUnit())
.icon(powerIncomeInfoDto.getIcon())
.width(100).build();
int index = 1;
for (TableHeadersDto tableHeadersDto : columns) {
if (index < 10 && "hashrate".equals(tableHeadersDto.getType())){
if (column.getLabel().equals(tableHeadersDto.getLabel())){
setDynamicPower(index,machineInfo,powerIncomeInfoDto);
return;
}else{
index++;
}
}
}
if (index <= 10){
setDynamicPower(index,machineInfo,powerIncomeInfoDto);
column.setKey("c"+index);
columns.add(column);
}
}
private void setDynamicPower(int index,MachineInfoDto machineInfo,PowerIncomeInfoDto powerIncomeInfoDto){
switch (index){
case 1:
machineInfo.setC1(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
case 2:
machineInfo.setC2(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
case 3:
machineInfo.setC3(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
case 4:
machineInfo.setC4(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
case 5:
machineInfo.setC5(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
case 6:
machineInfo.setC6(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
case 7:
machineInfo.setC7(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
case 8:
machineInfo.setC8(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
case 9:
machineInfo.setC9(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
case 10:
machineInfo.setC10(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
break;
}
}
@Override
public PageResult<SellerMachineInfoDto> getShopMachineListForSeller(SellerMachineVo sellerMachineVo) {
LeaseShop leaseShop = getShopById();
if (leaseShop == null){
//不存在店铺
return PageResult.success(new ArrayList<>());
}
PageHelper.startPage(sellerMachineVo.getPageNum(), sellerMachineVo.getPageSize());
List<SellerMachineInfoDto> machineInfoDtoList = leaseMachineMapper.getShopMachineListForSeller(sellerMachineVo,leaseShop.getId());
PageInfo<SellerMachineInfoDto> pageInfo = new PageInfo<>(machineInfoDtoList);
if (machineInfoDtoList.isEmpty()){
//没有矿机
return PageResult.success(new ArrayList<>());
}
PageResult<SellerMachineInfoDto> success = PageResult.success(machineInfoDtoList);
//获取矿机配置信息
List<AsicCoinAndAlgoDto> coinAndAlgoList = leaseMachineMapper.getCoinAndAlgoList(success.getRows());
Map<Long, List<AsicCoinAndAlgoDto>> collect1 = coinAndAlgoList.stream().collect(Collectors.groupingBy(AsicCoinAndAlgoDto::getProductMachineId));
//价格配置信息
List<MachinePayTypeDto> machinePriceList = leaseMachineMapper.getMachinePriceList(success.getRows());
Map<Long, List<MachinePayTypeDto>> collect = machinePriceList.stream().collect(Collectors.groupingBy(MachinePayTypeDto::getProductMachineId));
//能否上架
Map<Long, MachineEffectDto> longMachineEffectDtoMap = leaseMachineMapper.checkIsEffect(success.getRows());
for (SellerMachineInfoDto row : success.getRows()) {
MachineEffectDto machineEffectDto = longMachineEffectDtoMap.get(row.getId());
row.setEffect(machineEffectDto != null ? machineEffectDto.getEffect() : 0);
row.setPriceList(collect.get(row.getId()));
row.setCoinAndAlgoList(collect1.get(row.getId()));
}
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
/**
* 分页内排序
* @param shopMachineVo 查询条件
* @param machineInfoDtoList 钱包信息
* @return 查询条件
*/
public List<MachineInfoDto> sorted(List<MachineInfoDto> machineInfoDtoList, ShopMachineVo shopMachineVo){
if (shopMachineVo.getPriceSort() != null) {
Comparator<MachineInfoDto> priceComparator = shopMachineVo.getPriceSort() ?
Comparator.comparing(MachineInfoDto::getPrice) :
Comparator.comparing(MachineInfoDto::getPrice).reversed();
return machineInfoDtoList.stream()
.sorted(priceComparator)
.collect(Collectors.toList());
} else if (shopMachineVo.getPowerSort() != null) {
Comparator<MachineInfoDto> powerComparator = shopMachineVo.getPowerSort() ?
Comparator.comparing(MachineInfoDto::getTheoryPower) :
Comparator.comparing(MachineInfoDto::getTheoryPower).reversed();
return machineInfoDtoList.stream()
.sorted(powerComparator)
.collect(Collectors.toList());
}else {
return machineInfoDtoList;
}
}
public ShopMachineVo buildQuery(ShopMachineVo shopMachineVo,PayConfigDto payConfigDto){
if (StringUtils.isEmpty(shopMachineVo.getChain()) && StringUtils.isEmpty(shopMachineVo.getCoin())){
shopMachineVo.setChain(payConfigDto.getPayChain());
shopMachineVo.setCoin(payConfigDto.getPayCoin());
}
//BigDecimal power = PowerUnit.getPower(shopMachineVo.getUnit()).divide(BigDecimal.valueOf(1000 * 1000),2, RoundingMode.HALF_UP);
//shopMachineVo.setMaxPower(shopMachineVo.getMaxPower().multiply(power));
//shopMachineVo.setMinPower(shopMachineVo.getMinPower().multiply(power));
////算力设置
//if (shopMachineVo.getMaxPower().compareTo(shopMachineVo.getMinPower()) < 0){
// shopMachineVo.setMaxPower(shopMachineVo.getMinPower());
// shopMachineVo.setMinPower(shopMachineVo.getMaxPower());
//}
////功耗设置
//if (shopMachineVo.getMaxPowerDissipation().compareTo(shopMachineVo.getMinPowerDissipation()) < 0){
// shopMachineVo.setMaxPowerDissipation(shopMachineVo.getMinPowerDissipation());
// shopMachineVo.setMinPowerDissipation(shopMachineVo.getMaxPowerDissipation());
//}
//价格设置
if (shopMachineVo.getMaxPrice().compareTo(shopMachineVo.getMinPrice()) < 0){
shopMachineVo.setMaxPrice(shopMachineVo.getMinPrice());
shopMachineVo.setMinPrice(shopMachineVo.getMaxPrice());
}
return shopMachineVo;
}
@Override
@Transactional
public Result<String> addAsicMachine(AsicMachineParamsVo asicMachineParamsVo) {
if(asicMachineParamsVo.getPriceList().isEmpty()){
return Result.fail("添加ASIC矿机失败,请先绑定收款钱包");
}
LeaseShop leaseShop = getShopById();
if (leaseShop == null){
return Result.fail("添加ASIC矿机失败,未找到商铺,请重试");
}
//新增lease_machine主表信息
LeaseMachine machine = LeaseMachine.builder()
.hostMac(UuidGeneratorUtil.generateUuidWithoutHyphen())
.shopId(leaseShop.getId())
.type(false)
.maxLeaseDays(asicMachineParamsVo.getMaxLeaseDays())
.saleNumbers(asicMachineParamsVo.getSaleNumbers())
.canSaleNumbers(asicMachineParamsVo.getSaleNumbers())
.build();
int machineInsert = leaseMachineMapper.insert(machine);
//新增lease_asic_coin_power_config 配置信息表信息 + lease_machine_price 矿机价格表信息
if (machineInsert > 0){
List<LeaseMachineConfig> collect = asicMachineParamsVo.getCoinAndAlgoList().stream().map(
coinAndAlgo -> LeaseMachineConfig.builder()
.machineId(machine.getId())
.name(asicMachineParamsVo.getName())
.powerDissipation(asicMachineParamsVo.getPowerDissipation())
.coin(coinAndAlgo.getCoin())
.algorithm(coinAndAlgo.getAlgorithm())
.hashrate(coinAndAlgo.getTheoryPower())
.unit(coinAndAlgo.getUnit())
.build()
).collect(Collectors.toList());
List<LeaseMachinePrice> collect1 = asicMachineParamsVo.getPriceList().stream()
.map(machinePayTypeVo ->
LeaseMachinePrice.builder()
.machineId(machine.getId())
.price(machinePayTypeVo.getPrice())
.coin(machinePayTypeVo.getCoin())
.chain(machinePayTypeVo.getChain())
.build()
).collect(Collectors.toList());
boolean b1 = leaseMachinePriceService.saveBatch(collect1);
boolean b = leaseMachineConfigService.saveBatch(collect);
if (!b && !b1){
throw new MachineException("添加asic矿机币价及算力信息失败");
}
return Result.success("添加asic矿机成功");
}
return Result.fail("添加ASIC矿机失败,请重试");
}
@Override
@Transactional
public Result<String> updateAsicMachine(AsicMachineParamsVo asicMachineParamsVo) {
//修改lease_machine主表信息
LeaseMachine machine = LeaseMachine.builder()
.id(asicMachineParamsVo.getId())
.maxLeaseDays(asicMachineParamsVo.getMaxLeaseDays())
.saleNumbers(asicMachineParamsVo.getSaleNumbers())
.state(asicMachineParamsVo.getState())
.build();
int machineUpdate = leaseMachineMapper.updateById(machine);
//修改lease_machine_price 矿机价格表信息 + 修改lease_asic_coin_power_config 配置信息表信息
if (machineUpdate > 0){
List<LeaseMachinePrice> collect = asicMachineParamsVo.getPriceList().stream().map(
machinePayTypeVo ->
LeaseMachinePrice.builder()
.id(machinePayTypeVo.getPayTypeId())
.price(machinePayTypeVo.getPrice())
.build()
).collect(Collectors.toList());
boolean b = leaseMachinePriceService.updateBatchById(collect);
List<LeaseMachineConfig> collect1 = asicMachineParamsVo.getCoinAndAlgoList().stream().map(coinAndAlgo ->
LeaseMachineConfig.builder()
.id(coinAndAlgo.getCoinAndPowerId())
.machineId(machine.getId())
.name(asicMachineParamsVo.getName())
.coin(coinAndAlgo.getCoin())
.hashrate(coinAndAlgo.getTheoryPower())
.algorithm(coinAndAlgo.getAlgorithm())
.unit(coinAndAlgo.getUnit())
.powerDissipation(asicMachineParamsVo.getPowerDissipation())
.build()
).collect(Collectors.toList());
boolean b1 = leaseMachineConfigService.saveOrUpdateBatch(collect1);
if (!b && !b1){
throw new MachineException("修改asic矿机币价及算力信息失败");
}
return Result.success("修改ASIC矿机成功");
}
return Result.fail("修改ASIC矿机失败,请重试");
}
@Override
@Transactional
public Result<String> updateGpuMachine(List<GpuMachineParamsVo> gpuMachineParamsVoList) {
//校验能否上架
for (GpuMachineParamsVo gpuMachineParamsVo : gpuMachineParamsVoList) {
//修改lease_machine主表信息
LeaseMachine machine = LeaseMachine.builder()
.id(gpuMachineParamsVo.getId())
.maxLeaseDays(gpuMachineParamsVo.getMaxLeaseDays())
.state(gpuMachineParamsVo.getState())
.build();
int machineUpdate = leaseMachineMapper.updateById(machine);
//修改lease_machine_price 矿机价格表信息
if (machineUpdate > 0){
List<MachinePayTypeVo> priceList = gpuMachineParamsVo.getPriceList();
for (MachinePayTypeVo machinePayTypeVo : priceList) {
LeaseMachinePrice build = LeaseMachinePrice.builder()
.id(machinePayTypeVo.getPayTypeId())
.price(machinePayTypeVo.getPrice())
.chain(machinePayTypeVo.getChain())
.coin(machinePayTypeVo.getCoin())
.machineId(machine.getId())
.build();
if (build.getId() == null || build.getId() == 0){
leaseMachinePriceMapper.insert(build);
}else{
leaseMachinePriceMapper.updateById(build);
}
}
}
}
return Result.success("修改GPU矿机成功") ;
}
@Override
@Transactional
public Result<String> updateMachineState(MachineStateVo machineStateVo) {
leaseMachineMapper.updateById(LeaseMachine.builder().id(machineStateVo.getId()).state(machineStateVo.getState()).build());
return machineStateVo.getState() ? Result.success("下架成功") : Result.success("上架成功");
}
@Override
public Result<String> deleteMachine(BaseVo baseVo) {
//TODO 删除之前需要判断是否存在订单
leaseMachineMapper.updateById(LeaseMachine.builder().id(baseVo.getId()).del(true).build());
//删除售价
leaseMachinePriceMapper.update(LeaseMachinePrice.builder().del(true).build(),new LambdaQueryWrapper<LeaseMachinePrice>()
.eq(LeaseMachinePrice::getMachineId,baseVo.getId()));
//ASIC/GPU 矿机删除配置信息
leaseMachineConfigMapper.update(LeaseMachineConfig.builder().del(true).build(),
new LambdaQueryWrapper<LeaseMachineConfig>().eq(LeaseMachineConfig::getMachineId,baseVo.getId()));
return Result.success("删除成功");
}
@Override
public Result<List<String>> getSupportCoin() {
List<String> supportCoin = leaseMachineMapper.getSupportCoin();
return Result.success(supportCoin);
}
@Override
public Result<List<String>> getSupportAlgo(String coin) {
List<String> supportAlgo = leaseMachineMapper.getSupportAlgo(coin);
return Result.success(supportAlgo);
}
}

View File

@@ -0,0 +1,20 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseNexaMachineAvgPower;
import com.m2pool.lease.mapper.LeaseNexaMachineAvgPowerMapper;
import com.m2pool.lease.service.LeaseNexaMachineAvgPowerService;
import org.springframework.stereotype.Service;
/**
* <p>
* 矿池nexa机器实时平均算力 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-29
*/
@Service
public class LeaseNexaMachineAvgPowerServiceImpl extends ServiceImpl<LeaseNexaMachineAvgPowerMapper, LeaseNexaMachineAvgPower> implements LeaseNexaMachineAvgPowerService {
}

View File

@@ -0,0 +1,20 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseNexaMachinePower;
import com.m2pool.lease.mapper.LeaseNexaMachinePowerMapper;
import com.m2pool.lease.service.LeaseNexaMachinePowerService;
import org.springframework.stereotype.Service;
/**
* <p>
* 已售商品矿工实时算力表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-25
*/
@Service
public class LeaseNexaMachinePowerServiceImpl extends ServiceImpl<LeaseNexaMachinePowerMapper, LeaseNexaMachinePower> implements LeaseNexaMachinePowerService {
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseOrderItem;
import com.m2pool.lease.mapper.LeaseOrderItemMapper;
import com.m2pool.lease.service.LeaseOrderItemService;
import org.springframework.stereotype.Service;
/**
* <p>
* 订单明细表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Service
public class LeaseOrderItemServiceImpl extends ServiceImpl<LeaseOrderItemMapper, LeaseOrderItem> implements LeaseOrderItemService {
}

View File

@@ -0,0 +1,22 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeasePayRecordMessage;
import com.m2pool.lease.entity.LeasePayRecordMessageInfo;
import com.m2pool.lease.mapper.LeasePayRecordMessageInfoMapper;
import com.m2pool.lease.mapper.LeasePayRecordMessageMapper;
import com.m2pool.lease.service.LeasePayRecordMessageInfoService;
import com.m2pool.lease.service.LeasePayRecordMessageService;
import org.springframework.stereotype.Service;
/**
* <p>
* service层支付
* </p>
*
* @author yyb
* @since 2025-09-10
*/
@Service
public class LeasePayRecordMessageInfoServiceImpl extends ServiceImpl<LeasePayRecordMessageInfoMapper, LeasePayRecordMessageInfo> implements LeasePayRecordMessageInfoService {
}

View File

@@ -0,0 +1,19 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeasePayRecordMessage;
import com.m2pool.lease.mapper.LeasePayRecordMessageMapper;
import com.m2pool.lease.service.LeasePayRecordMessageService;
import org.springframework.stereotype.Service;
/**
* <p>
* service层支付
* </p>
*
* @author yyb
* @since 2025-09-10
*/
@Service
public class LeasePayRecordMessageServiceImpl extends ServiceImpl<LeasePayRecordMessageMapper, LeasePayRecordMessage> implements LeasePayRecordMessageService {
}

View File

@@ -0,0 +1,497 @@
package com.m2pool.lease.service.impl;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.constant.PaymentStatus;
import com.m2pool.lease.dto.PaymentCallbackDto;
import com.m2pool.lease.dto.PaymentRecordDto;
import com.m2pool.lease.mq.message.RabbitmqPoolProxyMessage;
import com.m2pool.lease.dto.Result;
import com.m2pool.lease.entity.LeaseOrderInfo;
import com.m2pool.lease.entity.LeaseOrderItem;
import com.m2pool.lease.entity.LeasePaymentRecord;
import com.m2pool.lease.exception.PaymentException;
import com.m2pool.lease.mapper.LeaseOrderInfoMapper;
import com.m2pool.lease.mapper.LeaseOrderItemMapper;
import com.m2pool.lease.mapper.LeasePaymentRecordMapper;
import com.m2pool.lease.service.LeasePaymentRecordService;
import com.m2pool.lease.service.LeaseUserOwnedProductService;
import com.m2pool.lease.utils.HttpPayUtils;
import com.m2pool.lease.vo.CheckPayStatusVo;
import com.m2pool.lease.vo.OrderVo;
import com.m2pool.lease.vo.PayVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import static com.m2pool.lease.constant.OrderStatus.FULLY_PAID;
import static com.m2pool.lease.constant.OrderStatus.PARTIALLY_PAID;
import static com.m2pool.lease.constant.PaymentStatus.*;
import static com.m2pool.lease.constant.RabbitmqConstant.POOL_PROXY_QUEUE_NAME;
import static com.m2pool.lease.utils.HttpPayUtils.PAY_ETH;
/**
* <p>
* 支付记录表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Service
public class LeasePaymentRecordServiceImpl extends ServiceImpl<LeasePaymentRecordMapper, LeasePaymentRecord> implements LeasePaymentRecordService {
@Resource
private RabbitTemplate rabbitTemplate;
@Resource
private LeaseOrderItemMapper leaseOrderItemMapper;
@Resource
private LeasePaymentRecordMapper leasePaymentRecordMapper;
@Resource
private ThreadPoolTaskExecutor customThreadPool;
@Resource
private LeaseOrderInfoMapper leaseOrderInfoMapper;
@Resource
private LeaseUserOwnedProductService leaseUserOwnedProductService;
@Override
@Transactional
public Result<List<PaymentRecordDto>> addPayOrder(OrderVo orderVo) {
//1.根据订单id查询订单详情信息
List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
.eq(LeaseOrderItem::getOrderId, orderVo.getOrderId()));
//2.按商品ID分组并生成支付订单列表
Map<Long, List<LeaseOrderItem>> productItemsMap = leaseOrderItems.stream()
.collect(Collectors.groupingBy(LeaseOrderItem::getProductId));
//3.生成支付订单列表 + 封装返回对象
List<PaymentRecordDto> paymentRecordDTOs = new ArrayList<>();
List<LeasePaymentRecord> paymentRecords = productItemsMap.values().stream()
.map(items -> {
LeaseOrderItem firstItem = items.get(0);
BigDecimal totalAmount = items.stream()
.map(LeaseOrderItem::getPrice)
.reduce(BigDecimal.ZERO, BigDecimal::add);
Long orderId = orderVo.getOrderId();
Long productId = firstItem.getProductId();
String payCoin = firstItem.getPayCoin();
String address = firstItem.getAddress();
paymentRecordDTOs.add(PaymentRecordDto.builder()
.payCoin(payCoin)
.amount(totalAmount)
.payAddress(address)
.build());
return LeasePaymentRecord.builder()
.orderId(orderId)
.productId(productId)
.payCoin(payCoin)
.amount(totalAmount)
.payAddress(address)
.build();
})
.collect(Collectors.toList());
//4.保存支付订单
boolean saved = saveBatch(paymentRecords);
if (saved) {
return Result.success(paymentRecordDTOs);
} else {
return Result.fail("生成支付订单失败");
}
}
@Override
public Result<List<PaymentRecordDto>> getPayOrderByOrderId(OrderVo orderVo) {
List<LeasePaymentRecord> leasePaymentRecords = leasePaymentRecordMapper.selectList(new LambdaQueryWrapper<LeasePaymentRecord>()
.eq(LeasePaymentRecord::getOrderId, orderVo.getOrderId())
.eq(LeasePaymentRecord::getDel, false));
List<PaymentRecordDto> collect = leasePaymentRecords.stream()
.map(record -> PaymentRecordDto.builder()
.id(record.getId())
.payCoin(record.getPayCoin())
.amount(record.getAmount())
.payAddress(record.getPayAddress())
.status(record.getStatus())
.img(record.getQrcode())
.build()).collect(Collectors.toList());
return Result.success(collect);
}
@Override
@Transactional
public Result<List<PaymentCallbackDto>> paymentCallbackBatch(List<CheckPayStatusVo> checkPayStatusVoList) {
List<PaymentCallbackDto> paymentCallbackDTOs = new ArrayList<>();
//1.查询处于待支付中状态2的订单
List<Long> payIds = checkPayStatusVoList.stream().map(CheckPayStatusVo::getId).collect(Collectors.toList());
List<LeasePaymentRecord> leasePaymentRecords = leasePaymentRecordMapper.selectList(new LambdaQueryWrapper<LeasePaymentRecord>()
.in(LeasePaymentRecord::getId, payIds)
.eq(LeasePaymentRecord::getDel, true)
.nested(wrapper -> wrapper
.eq(LeasePaymentRecord::getStatus, 2)
.or()
.eq(LeasePaymentRecord::getStatus, 10)));
List<Long> orderIds = leasePaymentRecords.stream().map(LeasePaymentRecord::getOrderId).collect(Collectors.toList());
//2.根据订单id查询订单详情信息
List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
.in(LeaseOrderItem::getOrderId, orderIds));
//3.按商店id分组
Map<Long, List<LeaseOrderItem>> productItemsMap = leaseOrderItems.stream()
.collect(Collectors.groupingBy(LeaseOrderItem::getShopId));
//记录是否所有都支付成功
int isAll = 0;
//4.按店铺分组---->合并店铺下所有支付订单----> 按所有总交易金额 去填充这些订单---->填充慢则表示这一笔订单支付成功----> 发货
for (LeasePaymentRecord record : leasePaymentRecords) {
//4.1 调用三方api校验支付是否成功
PaymentCallbackDto paymentCallbackDto = paymentCallback(record);
if (paymentCallbackDto.getIsPayAll() == 1){
//4.2 修改商品售出状态 + 新增机器到已购表中 (为了保证成功需要通过消息中间件达成最终一致性 demo暂时不修改)
List<LeaseOrderItem> leaseOrderItemList = productItemsMap.get(record.getShopId());
boolean isSuccess = leaseUserOwnedProductService.afterPaySuccessTodoSomeEvent(leaseOrderItemList);
if (!isSuccess){
return Result.fail("支付校验成功√-->货款已付清√-->发货失败×。请提交工单发送订单给客服或者通过聊天系统联系客服解决");
}
record.setStatus(1);
int i = leasePaymentRecordMapper.updateById(record);
isAll += i;
//4.3 发送rabbitmq消息给矿池代理
sendRabbitmqMessage(leaseOrderItemList);
}else if (paymentCallbackDto.getIsPayAll() == 10){
//支付了部分货款改状态---但是不发货
leasePaymentRecordMapper.updateById(LeasePaymentRecord.builder().id(record.getId()).status(10).build());
}
paymentCallbackDto.setTotalAmount(record.getAmount());
paymentCallbackDTOs.add(paymentCallbackDto);
}
//5.修改订单状态为 1全部已支付 10部分已支付
int status = isAll == leasePaymentRecords.size() ? 1 : 10;
Long orderId = leasePaymentRecords.get(0).getOrderId();
int i = leaseOrderInfoMapper.updateById(LeaseOrderInfo.builder().id(orderId).status(status).build());
if (i > 0){
return Result.success(paymentCallbackDTOs);
}else {
return Result.fail("校验失败");
}
}
@Override
@Transactional
public Result<PaymentCallbackDto> paymentCallbackByPayId(CheckPayStatusVo baseVo) {
LeasePaymentRecord record = leasePaymentRecordMapper.selectById(baseVo.getId());
record.setFrom(baseVo.getForm());
record.setHash(baseVo.getHash());
//支付状态为2 待支付 或者 10 支付成功--已支付部分货款 两种状态可校验
if (record.getStatus() == 10 || record.getStatus() == 2){
//1.根据订单id + 店铺id 查询订单详情信息 支付订单按shop分的不再按商品分
List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
.eq(LeaseOrderItem::getOrderId, record.getOrderId()).eq(LeaseOrderItem::getShopId, record.getShopId()));
//2.调用三方api校验支付是否成功
PaymentCallbackDto paymentCallbackDto = paymentCallback(record);
if (paymentCallbackDto.getIsPayAll() == 1){
boolean isSuccess = leaseUserOwnedProductService.afterPaySuccessTodoSomeEvent(leaseOrderItems);
if (!isSuccess){
return Result.fail("支付校验成功√-->货款已付清√-->发货失败×。请提交工单发送订单给客服或者通过聊天系统联系客服解决");
}
record.setStatus(1);
leasePaymentRecordMapper.updateById(record);
//2.1 发送rabbitmq消息给矿池代理
sendRabbitmqMessage(leaseOrderItems);
} else if (paymentCallbackDto.getIsPayAll() == 10){
//2.2 支付了部分货款改状态---但是不发货
leasePaymentRecordMapper.updateById(LeasePaymentRecord.builder().id(record.getId()).status(10).build());
}
//3.查询订单是否下所有支付订单都已支付完成
Long l = leasePaymentRecordMapper.selectCount(new LambdaQueryWrapper<LeasePaymentRecord>()
.eq(LeasePaymentRecord::getOrderId, record.getOrderId())
.eq(LeasePaymentRecord::getDel, true)
.ne(LeasePaymentRecord::getStatus,1));
//4.修改订单为全部已支付
if (l == 0){
leaseOrderInfoMapper.updateById(LeaseOrderInfo.builder().id(record.getOrderId()).status(1).build());
}
return Result.success(paymentCallbackDto);
}
return Result.fail("验证失败,该订单状态不为支付成功未验证状态");
}
@Override
@Transactional
public void paymentCallbackTask(List<LeasePaymentRecord> leasePaymentRecordList) {
List<Long> orderIds = leasePaymentRecordList.stream().map(LeasePaymentRecord::getOrderId).distinct().collect(Collectors.toList());
//1---根据订单id查询订单详情信息
List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
.in(LeaseOrderItem::getOrderId, orderIds));
//2---按商店id - 订单id 分组
Map<String, List<LeaseOrderItem>> productItemsMap = leaseOrderItems.stream()
.collect(Collectors.groupingBy(
item -> item.getShopId() + "-" + item.getOrderId()
));
//3---支付订单按支付地址分组 校验
Map<String, List<LeasePaymentRecord>> shopMaps = leasePaymentRecordList.stream().collect(Collectors.groupingBy(LeasePaymentRecord::getPayAddress));
List<LeasePaymentRecord> afterCheckPaymentList = shopMaps.entrySet().stream()
.map(entry -> {
String key = entry.getKey();
List<LeasePaymentRecord> values = entry.getValue();
// 查找已经支付的金额
BigDecimal paySuccessAmount = values.stream().map(LeasePaymentRecord::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal alreadyPayAmount = getAlreadyPayAmount(key, values).subtract(paySuccessAmount);
// 在迭代过程中修改列表,使用 fori 循环避免 ConcurrentModificationException
for (int i = 0; i < values.size(); i++) {
LeasePaymentRecord leasePaymentRecord = values.get(i);
BigDecimal needPayAmount = leasePaymentRecord.getAmount();
BigDecimal payAmount = leasePaymentRecord.getPayAmount();
// 如果该支付订单已支付了部分金额 剩下需支付需减去该值
if (payAmount.compareTo(BigDecimal.ZERO) != 0) {
needPayAmount = needPayAmount.subtract(payAmount);
}
// 已支付金额 不等于 需支付总金额
if (payAmount.compareTo(needPayAmount) != 0) {
if (needPayAmount.compareTo(alreadyPayAmount) < 0) {
// 条件1: 交易记录金额大于需要支付的金额------> 该订单状态可改为 1全部已支付
alreadyPayAmount = alreadyPayAmount.subtract(needPayAmount);
leasePaymentRecord.setStatus(PAYMENT_SUCCESS_FULL.getCode());
leasePaymentRecord.setPayAmount(leasePaymentRecord.getAmount());
} else if (needPayAmount.compareTo(alreadyPayAmount) > 0 && alreadyPayAmount.compareTo(BigDecimal.ZERO) != 0) {
// 条件2: 交易记录金额小于需要支付的金额 ,但是交易记录金额不为0 ------> 该订单可改为状态 10部分已支付
alreadyPayAmount = BigDecimal.ZERO;
leasePaymentRecord.setStatus(PAYMENT_SUCCESS_PARTIAL.getCode());
leasePaymentRecord.setPayAmount(alreadyPayAmount);
} else if (PAYMENT_SUCCESS_PARTIAL.getCode() == leasePaymentRecord.getStatus()) {
// 条件3: 走到这里说明,交易金额已经分配完毕。 如果本身为部分已支付,直接去除
values.remove(i);
i--;
}
} else {
// 已支付金额 等于 需支付总金额 直接剔除
values.remove(i);
i--;
}
}
return values;
})
.flatMap(List::stream) // 展开嵌套的列表
.collect(Collectors.toList());
List<LeaseOrderItem> rabbitmqMessages = new ArrayList<>();
//4---更新支付状态变化的支付订单 + 支付订单为完成支付的 订单开始 发货
for (LeasePaymentRecord record : afterCheckPaymentList) {
//4.1全部支付成功的才能发货
if (PaymentStatus.PAYMENT_SUCCESS_FULL.getCode() == record.getStatus()){
String key = record.getShopId() + "-" + record.getOrderId();
List<LeaseOrderItem> leaseOrderItemList = productItemsMap.get(key);
leaseUserOwnedProductService.afterPaySuccessTodoSomeEvent(leaseOrderItemList);
rabbitmqMessages.addAll(leaseOrderItemList);
}
//4.2 修改支付订单的状态
leasePaymentRecordMapper.updateById(record);
}
//5---发送rabbitmq消息给矿池代理
sendRabbitmqMessage(rabbitmqMessages);
//6---修改普通订单状态
//统计每个普通订单对应的支付订单数量
Map<Long, Long> orderIdCountMap = leasePaymentRecordList.stream()
.collect(Collectors.groupingBy(LeasePaymentRecord::getOrderId, Collectors.counting()));
// 统计每个订单对应的支付已全部完成的数量
Map<Long, Long> fullPaidCountMap = leasePaymentRecordList.stream()
.filter(record -> record.getStatus() == PAYMENT_SUCCESS_FULL.getCode())
.collect(Collectors.groupingBy(LeasePaymentRecord::getOrderId, Collectors.counting()));
// 统计每个订单对应的部分已完成的数量
Map<Long, Long> partialPaidCountMap = leasePaymentRecordList.stream()
.filter(record -> record.getStatus() == PAYMENT_SUCCESS_PARTIAL.getCode())
.collect(Collectors.groupingBy(LeasePaymentRecord::getOrderId, Collectors.counting()));
// 遍历 orderIdCountMap更新订单状态
for (Map.Entry<Long, Long> entry : orderIdCountMap.entrySet()) {
Long orderId = entry.getKey();
Long totalCount = entry.getValue();
Long fullPaidCount = fullPaidCountMap.getOrDefault(orderId, 0L);
Long partialPaidCount = partialPaidCountMap.getOrDefault(orderId, 0L);
if (Objects.equals(fullPaidCount, totalCount)) {
// 全部已完成
leaseOrderInfoMapper.updateById(LeaseOrderInfo.builder().id(orderId).status(FULLY_PAID.getCode()).build());
//TODO 长连接联系前端支付已完成
} else if (partialPaidCount > 0) {
// 部分已完成
leaseOrderInfoMapper.updateById(LeaseOrderInfo.builder().id(orderId).status(PARTIALLY_PAID.getCode()).build());
}
}
}
/**
* 获取当前用户已支付的金额
* @param leasePaymentRecordList
* @return
*/
private BigDecimal getAlreadyPayAmount(String payAddress,List<LeasePaymentRecord> leasePaymentRecordList) {
LeasePaymentRecord leasePaymentRecord = leasePaymentRecordList.get(0);
PayVo build = PayVo.builder()
.ts(leasePaymentRecord.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond())
.address(payAddress)
.build();
HttpPayUtils.PaymentDto paymentDto = HttpPayUtils.doPost(PAY_ETH, JSONUtil.toJsonStr(build));
BigDecimal totalAmount = BigDecimal.ZERO;
List<HttpPayUtils.PaymentData> paymentData = handlerResponse(paymentDto);
for (HttpPayUtils.PaymentData result : paymentData){
String valueStr = result.getValue();
BigDecimal divisor = BigDecimal.TEN.pow(6);
BigDecimal resultAmount = new BigDecimal(valueStr).divide(divisor,6, RoundingMode.HALF_UP);
totalAmount = totalAmount.add(resultAmount);
}
return totalAmount;
}
/**
* 调用三方api 进行支付校验
* @param record
* @return
*/
private PaymentCallbackDto paymentCallback(LeasePaymentRecord record) {
PayVo build = PayVo.builder()
.ts(record.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond())
.coin(record.getPayCoin())
.amount(record.getAmount())
.address(record.getPayAddress())
.build();
HttpPayUtils.PaymentDto paymentDto = HttpPayUtils.doPost(PAY_ETH, JSONUtil.toJsonStr(build));
List<HttpPayUtils.PaymentData> paymentData = handlerResponse(paymentDto);
if (paymentData != null && !paymentData.isEmpty()){
return payIsSuccess(record, paymentData);
}else{
throw new PaymentException("验证失败,卖方不存在转账记录");
}
}
/**
* 校验代码
* @param record
* @param paymentData
* @return
*/
private PaymentCallbackDto payIsSuccess(LeasePaymentRecord record,List<HttpPayUtils.PaymentData> paymentData){
//待支付状态为2
int isPayAll = 2;
BigDecimal noPayAmount = record.getAmount();
for (HttpPayUtils.PaymentData result : paymentData){
String valueStr = result.getValue();
BigDecimal divisor = BigDecimal.TEN.pow(6);
BigDecimal resultAmount = new BigDecimal(valueStr).divide(divisor,6, RoundingMode.HALF_UP);
long timeStamp = Long.parseLong(result.getTimeStamp());
long ts = record.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
//交易hash 和 买家钱包地址 有一个校验通过即可(只适用于自营校验)
if (timeStamp >= ts && (result.getFrom().equals(record.getFrom()) || result.getHash().equals(record.getHash()))){
noPayAmount = noPayAmount.subtract(resultAmount);
//全部货款已支付
if (noPayAmount.compareTo(BigDecimal.ZERO) == 0){
isPayAll = 1;
break;
}
}
}
//已支付部分货款
if (noPayAmount.compareTo(record.getAmount()) != 0 && noPayAmount.compareTo(BigDecimal.ZERO) != 0){
isPayAll = 10;
}
return PaymentCallbackDto.builder().isPayAll(isPayAll).noPayAmount(noPayAmount).build();
}
/**
* 三方api调用异常
* @param paymentDto
* @return
*/
private List<HttpPayUtils.PaymentData> handlerResponse(HttpPayUtils.PaymentDto paymentDto){
if (paymentDto != null){
if (paymentDto.isResult() && paymentDto.getCode() == 0) {
// 支付成功,处理返回的交易数据
List<HttpPayUtils.PaymentData> transactions = paymentDto.getData();
return transactions;
} else {
// 支付失败,根据 code 处理不同错误
switch (paymentDto.getCode()) {
case -1:
throw new PaymentException("未转账");
case -2:
throw new PaymentException("coin参数不支持");
default:
throw new PaymentException("支付未知错误");
}
}
}else {
return null;
}
}
/**
* 发送rabbitmq消息给矿机代理
* @param leaseOrderItems
*/
public void sendRabbitmqMessage( List<LeaseOrderItem> leaseOrderItems) {
leaseOrderItems.forEach(item -> {
customThreadPool.execute(()->{
RabbitmqPoolProxyMessage rabbitmqPoolProxyMessage = RabbitmqPoolProxyMessage.builder()
.MethodID(0)
.Msg("")
.ID(item.getUser() + "-" + item.getMiner())
.Address(item.getAddress())
.build();
try {
rabbitTemplate.convertAndSend(POOL_PROXY_QUEUE_NAME, rabbitmqPoolProxyMessage);
} catch (Exception e) {
System.err.println("发送失败: " + e.getMessage());
}
});
});
}
}

View File

@@ -0,0 +1,20 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseProductIncome;
import com.m2pool.lease.mapper.LeaseProductIncomeMapper;
import com.m2pool.lease.service.LeaseProductIncomeService;
import org.springframework.stereotype.Service;
/**
* <p>
* 商品收益表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Service
public class LeaseProductIncomeServiceImpl extends ServiceImpl<LeaseProductIncomeMapper, LeaseProductIncome> implements LeaseProductIncomeService {
}

View File

@@ -0,0 +1,21 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseProductMachinePrice;
import com.m2pool.lease.mapper.LeaseProductMachinePriceMapper;
import com.m2pool.lease.service.LeaseProductMachinePriceService;
import org.springframework.stereotype.Service;
/**
* <p>
* 商品表对应的物品机器表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Service
public class LeaseProductMachinePriceServiceImpl extends ServiceImpl<LeaseProductMachinePriceMapper, LeaseProductMachinePrice> implements LeaseProductMachinePriceService {
}

View File

@@ -0,0 +1,360 @@
package com.m2pool.lease.service.impl;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.lease.constant.BlockInterval;
import com.m2pool.lease.redis.RedisCoinInfoKey;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.LeaseProduct;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.entity.LeaseProductMachinePrice;
import com.m2pool.lease.mapper.LeaseProductMachineMapper;
import com.m2pool.lease.mapper.LeaseProductMapper;
import com.m2pool.lease.redis.service.RedisService;
import com.m2pool.lease.service.LeaseProductMachinePriceService;
import com.m2pool.lease.service.LeaseProductMachineService;
import com.m2pool.lease.utils.PowerUnitUtils;
import com.m2pool.lease.utils.SecurityUtils;
import com.m2pool.lease.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* <p>
* 商品表对应的物品机器表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Service
public class LeaseProductMachineServiceImpl extends ServiceImpl<LeaseProductMachineMapper, LeaseProductMachine> implements LeaseProductMachineService {
@Resource
private LeaseProductMachineMapper leaseProductMachineMapper;
@Resource
private LeaseProductMapper leaseProductMapper;
@Resource
private RedisService redisService;
@Resource
private LeaseProductMachinePriceService leaseProductMachinePriceService;
@Autowired
private ApplicationContext applicationContext;
@Override
public Result<Map<String, List<UserMinerDto>> > getUserMinersList(UserMinerVo userMinerVo) {
String userId = SecurityUtils.getUsername();
//开发环境
//userId = "Eudora.law@outlook.com";
List<UserMinerDto> userMinersList = leaseProductMachineMapper.getUserMinersList(userId,userMinerVo.getCoin());
Map<String, List<UserMinerDto>> collect = userMinersList.stream().collect(Collectors.groupingBy(UserMinerDto::getCoin));
return Result.success(collect);
}
@Override
public Result<List<UserMinerDto>> getUserMachineList(UserMinerVo userMinerVo) {
//获取1天内的存在算力的机器这里user 和coin 组成了表的唯一键不用担心查询到其他用户相同的user和coin的矿机
List<UserMinerDto> minerMachines = leaseProductMachineMapper.getMinerMachines(userMinerVo.getUser(), userMinerVo.getCoin());
//根据矿工账号查询已经新增到商品机器表中的机器
List<String> minerMachinesIsSale = leaseProductMachineMapper.getMinerMachinesIsSale(userMinerVo.getUser(), userMinerVo.getCoin());
// 过滤 minerMachines 集合,只保留 miner 字段值不在 existingMiners 中的元素
minerMachines = minerMachines.stream()
.filter(dto -> !minerMachinesIsSale.contains(dto.getMiner()))
.peek(dto -> {
dto.setRealPower(dto.getRealPower().divide(BigDecimal.valueOf(24 * 60 * 60),2, RoundingMode.HALF_UP));
dto.setRealPower(dto.getRealPower().setScale(2, RoundingMode.HALF_UP));
})
.collect(Collectors.toList());
return Result.success(minerMachines);
}
@Override
public PageResult<ProductUpdateMachineDto> getMachineListForUpdate(ProductForUpdateMachineVo productForUpdateMachineVo) {
PageHelper.startPage(productForUpdateMachineVo.getPageNum(), productForUpdateMachineVo.getPageSize());
List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectList(new LambdaQueryWrapper<LeaseProductMachine>()
.eq(LeaseProductMachine::getProductId, productForUpdateMachineVo.getId()).eq(LeaseProductMachine::getDel,false));
PageInfo<LeaseProductMachine> pageInfo = new PageInfo<>(leaseProductMachines);
if (leaseProductMachines.isEmpty()){
//不存在租售的矿机
return PageResult.success(new ArrayList<>());
}
//获取矿机对应的币价
List<Long> machineIds = leaseProductMachines.stream().map(LeaseProductMachine::getId).collect(Collectors.toList());
List<MachinePayTypeDto> priceList = leaseProductMachineMapper.getPriceList(machineIds);
Map<Long, List<MachinePayTypeDto>> collect = priceList.stream().collect(Collectors.groupingBy(MachinePayTypeDto::getProductMachineId));
List<ProductUpdateMachineDto> productUpdateMachineDtos = leaseProductMachines.stream().map(leaseProductMachine ->
ProductUpdateMachineDto.builder()
.id(leaseProductMachine.getId())
.user(leaseProductMachine.getUser())
.type(leaseProductMachine.getType())
.miner(leaseProductMachine.getMiner())
.priceList(collect.get(leaseProductMachine.getId()))
.computingPower(leaseProductMachine.getComputingPower().setScale(2, RoundingMode.HALF_UP))
.theoryPower(leaseProductMachine.getTheoryPower())
.unit(leaseProductMachine.getUnit())
.maxLeaseDays(leaseProductMachine.getMaxLeaseDays())
.state(leaseProductMachine.getState())
.saleState(leaseProductMachine.getSaleState())
.powerDissipation(leaseProductMachine.getPowerDissipation())
.build()
).collect(Collectors.toList());
PageResult<ProductUpdateMachineDto> success = PageResult.success(productUpdateMachineDtos);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
@Override
@DSTransactional
public Result<String> addSingleOrBatchMachine(ProductMachineParamsVo productMachineParamsVo) {
LeaseProduct product = leaseProductMapper.selectById(productMachineParamsVo.getProductId());
String coin = product.getCoin();
if (coin == null){
return Result.fail("商品币种不能为空");
}
//封装需要添加的商品的机器
List<LeaseProductMachine> leaseProductMachines = new ArrayList<>();
List<ProductMachineURDVo> productMachineURDVos = productMachineParamsVo.getProductMachineURDVos();
Map<Integer,List<LeaseProductMachinePrice>> payTypeMap = new HashMap<>();
AtomicInteger index = new AtomicInteger(1);
productMachineURDVos.forEach(machine -> {
int andIncrement = index.getAndIncrement();
leaseProductMachines.add(LeaseProductMachine.builder()
.updateCount(andIncrement)
.shopId(product.getShopId())
.productId(productMachineParamsVo.getProductId())
.type(machine.getType() == null ? productMachineParamsVo.getType() : machine.getType())
.theoryPower(machine.getTheoryPower() == null ? productMachineParamsVo.getTheoryPower() : machine.getTheoryPower())
.powerDissipation(productMachineParamsVo.getPowerDissipation())
.cost(productMachineParamsVo.getCost())
.price(BigDecimal.ZERO)
.incomeRate(BigDecimal.ZERO)
.maxLeaseDays(machine.getMaxLeaseDays() == null ? productMachineParamsVo.getMaxLeaseDays() : machine.getMaxLeaseDays())
.unit(machine.getUnit() == null ? productMachineParamsVo.getUnit() : machine.getUnit())
.powerDissipation(machine.getPowerDissipation() == null ? productMachineParamsVo.getPowerDissipation() : machine.getPowerDissipation())
.user(machine.getUser())
.miner(machine.getMiner())
.coin(coin)
.state(machine.getState())
.del( false)
.saleState(0)
.build());
payTypeMap.put(andIncrement,machine.getPriceList().stream()
.map(payType -> LeaseProductMachinePrice.builder()
.price(payType.getPrice())
.coin(payType.getCoin())
.chain(payType.getChain())
.build())
.collect(Collectors.toList()));
});
//计算对应user+miner 一天的总算力
List<ProductMachineDto> nexaMinersv2 = leaseProductMachineMapper.getRecentlyFiveMinutesData(leaseProductMachines, product.getCoin());
// 创建一个 Map 用于存储 user 和 miner 组合对应的 ProductMachineDto 对象
Map<String, ProductMachineDto> machineDtoMap = nexaMinersv2.stream()
.collect(Collectors.toMap(
dto -> dto.getUser() + "-" + dto.getMiner(),
dto -> dto
));
String priceKey = RedisCoinInfoKey.getPiceKey(product.getCoin());
String rewardKey = RedisCoinInfoKey.getRewardKey(product.getCoin());
String mhsKey = RedisCoinInfoKey.getMhsKey(product.getCoin());
if (priceKey == null || rewardKey == null || mhsKey == null){
return Result.fail("添加商品失败,该币种挖矿机器暂时不支持");
}
BigDecimal price = redisService.getCacheBigDecimal(priceKey) == null ? BigDecimal.ZERO : redisService.getCacheBigDecimal(priceKey);
BigDecimal reward = redisService.getCacheBigDecimal(rewardKey) == null ? BigDecimal.ZERO : redisService.getCacheBigDecimal(rewardKey);
//全网算力单位是MH/s
BigDecimal netPower = redisService.getCacheBigDecimal(mhsKey) == null ? BigDecimal.ZERO : redisService.getCacheBigDecimal(mhsKey);
if (price == null){
return Result.fail("添加商品失败,未获取到"+product.getCoin()+"币的币价,请稍后重试");
}
if (reward == null){
return Result.fail("添加商品失败,未获取到"+product.getCoin()+"币的报快奖励,请稍后重试");
}
if (netPower == null){
return Result.fail("添加商品失败,未获取到"+product.getCoin()+"币的全网算力,请稍后重试");
}
List<LeaseProductMachine> collect = leaseProductMachines.stream().peek(productMachineURDVo -> {
//获取单机实际算力
String key = productMachineURDVo.getUser() + "-" + productMachineURDVo.getMiner();
ProductMachineDto productMachineDto = machineDtoMap.get(key);
BigDecimal singleTheoryMachineIncome = BigDecimal.ZERO;
BigDecimal computingPower = BigDecimal.ZERO;
if (productMachineDto != null && productMachineDto.getComputingPower() != null){
//计算矿机一天内实际每秒平均算力
computingPower = PowerUnitUtils.getPower(productMachineURDVo.getUnit(), productMachineDto.getComputingPower()
.multiply(BigDecimal.valueOf(1000 * 1000))
.divide(BigDecimal.valueOf(24 * 60 * 60), 2, RoundingMode.HALF_UP));
BigDecimal power = PowerUnitUtils.getPower(productMachineURDVo.getUnit(), netPower.multiply(BigDecimal.valueOf(1000 * 1000)));
//理论收益 = 矿机算力/全网算力 * 24h /出块间隔秒数 * 单块奖励redis中nexa:reward
singleTheoryMachineIncome = computingPower.divide( power,6, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(24 * 60 * 60)
.divide(BlockInterval.getBlockCountByCoinName(product.getCoin()), 6, RoundingMode.HALF_UP))
.multiply(reward)
;
}
productMachineURDVo.setShopId(product.getShopId());
productMachineURDVo.setComputingPower(computingPower);
productMachineURDVo.setTheoryIncome(singleTheoryMachineIncome);
}).collect(Collectors.toList());
//新增矿机 索引改为普通联合索引
LeaseProductMachineServiceImpl service = applicationContext.getBean(LeaseProductMachineServiceImpl.class);
//TODO 修改,还是得用唯一索引
//leaseProductMachineMapper.saveOrUpdateBatchs(collect);
boolean b = service.saveBatch(collect);
if (b){
//修改商品的价格范围 及商品下机器库存数量
updatePriceRange(product.getId());
List<LeaseProductMachinePrice> list = new ArrayList<>();
for (LeaseProductMachine leaseProductMachine : collect) {
List<LeaseProductMachinePrice> leaseProductMachinePrices = payTypeMap.get(leaseProductMachine.getUpdateCount());
list.addAll(leaseProductMachinePrices.stream()
.peek(leaseProductMachinePrice -> leaseProductMachinePrice.setProductMachineId(leaseProductMachine.getId()))
.collect(Collectors.toList()));
}
//修改机器配置
leaseProductMachinePriceService.saveBatch(list);
return Result.success("添加成功,添加矿机数:"+collect.size());
}
return Result.fail("添加失败");
}
@Override
@Transactional
public Result<String> updateMachine(List<ProductUpdateMachineVo> productUpdateMachineVoList) {
List<Long> ids = new ArrayList<>();
List<LeaseProductMachine> leaseProductMachines = new ArrayList<>();
List<LeaseProductMachinePrice> list = new ArrayList<>();
productUpdateMachineVoList.forEach(machine -> {
leaseProductMachines.add( LeaseProductMachine.builder()
.id(machine.getId())
.type(machine.getType())
.theoryPower(machine.getTheoryPower())
.unit(machine.getUnit())
.powerDissipation(machine.getPowerDissipation())
//.electricityBill(machine.getElectricityBill())
.incomeRate(machine.getIncomeRate())
.price(machine.getPrice())
.maxLeaseDays(machine.getMaxLeaseDays())
.user(machine.getUser())
.miner(machine.getMiner())
.state(machine.getState())
.build());
list.addAll(machine.getPriceList().stream()
.map(payType -> LeaseProductMachinePrice.builder()
.id(payType.getPayTypeId())
.price(payType.getPrice())
.chain(payType.getChain())
.build())
.collect(Collectors.toList()));
if (machine.getState() == 1){
ids.add(machine.getId());
}
});
if (!ids.isEmpty()){
List<LeaseProductMachine> leaseProductMachines1 = leaseProductMachineMapper.selectBatchIds(ids);
long count = leaseProductMachines1.stream()
.filter(leaseProductMachine -> leaseProductMachine.getSaleState() == 1).count();
if (count >= 1){
return Result.fail("商品修改失败,部分矿机租约已存在,不能下架");
}
}
boolean b = updateBatchById(leaseProductMachines);
if (b){
LeaseProductMachine leaseProductMachine = leaseProductMachineMapper.selectById(productUpdateMachineVoList.get(0).getId());
//修改商品的价格范围
updatePriceRange(leaseProductMachine.getProductId());
leaseProductMachinePriceService.updateBatchById(list);
return Result.success("修改成功");
}
return Result.fail("修改失败");
}
@Override
@Transactional
public Result<String> deleteMachine(BaseVo baseVo) {
LeaseProductMachine leaseProductMachine = leaseProductMachineMapper.selectById(baseVo.getId());
if (leaseProductMachine.getSaleState() != 0){
return Result.fail("该商品已售出,暂时不能删除");
}
//修改商品的价格范围 及商品下机器库存数量
boolean b = updateById(LeaseProductMachine.builder().id(baseVo.getId()).del(true).build());
if (b){
updatePriceRange(leaseProductMachine.getProductId());
//删除售价
leaseProductMachinePriceService.updateById(LeaseProductMachinePrice.builder().id(baseVo.getId()).del(true).build());
return Result.success("删除成功");
}
return Result.fail("删除失败");
}
/**
* 修改商品价格范围
* @param productId
*/
public void updatePriceRange(Long productId){
//修改商品的价格范围
PriceDto priceDto = leaseProductMachineMapper.getPriceRange(productId);
BigDecimal maxPrice = BigDecimal.ZERO;
BigDecimal minPrice = BigDecimal.ZERO;
Integer totalMachineNumber = 0;
if (priceDto != null){
totalMachineNumber = priceDto.getTotalMachineNumber();
maxPrice = priceDto.getPriceMax();
minPrice = priceDto.getPriceMin();
}
LeaseProduct build = LeaseProduct.builder().id(productId)
.minPrice(minPrice)
.maxPrice(maxPrice)
.totalMachineNumber(totalMachineNumber )
.build();
leaseProductMapper.updateById(build);
}
@Override
public Result<BigDecimal> calculatePrice(PriceCalculateVo priceCalculateVo) {
//TODO 第三方计算器
return null;
}
}

View File

@@ -0,0 +1,539 @@
package com.m2pool.lease.service.impl;
import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.lease.constant.Algorithm;
import com.m2pool.lease.constant.BlockInterval;
import com.m2pool.lease.constant.PowerUnit;
import com.m2pool.lease.redis.RedisCoinInfoKey;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.*;
import com.m2pool.lease.exception.ProductSoldOutException;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.redis.service.RedisService;
import com.m2pool.lease.service.LeaseProductMachinePriceService;
import com.m2pool.lease.service.LeaseProductService;
import com.m2pool.lease.service.LeaseShopConfigService;
import com.m2pool.lease.utils.PowerUnitUtils;
import com.m2pool.lease.utils.QrCodeUtils;
import com.m2pool.lease.utils.SecurityUtils;
import com.m2pool.lease.utils.WalletRuleCheckUtils;
import com.m2pool.lease.vo.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
* 商品表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Service
public class LeaseProductServiceImpl extends ServiceImpl<LeaseProductMapper, LeaseProduct> implements LeaseProductService {
@Resource
private LeaseProductMachineMapper leaseProductMachineMapper;
@Resource
private LeaseProductMapper leaseProductMapper;
@Resource
private RedisService redisService;
@Resource
private LeaseShopMapper leaseShopMapper;
@Resource
private LeaseShopConfigMapper leaseShopConfigMapper;
@Resource
private LeaseProductMachinePriceService leaseProductMachinePriceService;
@Resource
private LeaseShopConfigService leaseShopConfigService;
@Resource
private LeaseProductMachinePriceMapper leaseProductMachinePriceMapper;
@Override
public PageResult<ProductDto> getProductList(ProductPageVo productPageVo) {
Long shopId = 0L;
System.out.println("用户邮箱参数:"+productPageVo.getUserEmail());
//1.用户邮箱参数不为空,则表示个人中心的商品列表。这个时候能看到下架的商品
if (!StringUtils.isEmpty(productPageVo.getUserEmail())){
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.eq(LeaseShop::getUserEmail, productPageVo.getUserEmail()));
if (leaseShop != null){
shopId = leaseShop.getId();
}else{
//不存在出售商品
return PageResult.success(new ArrayList<>());
}
}
PageHelper.startPage(productPageVo.getPageNum(), productPageVo.getPageSize());
List<ProductDto> leaseProducts = leaseProductMapper.getProductListForShopAndUserCenter(productPageVo.getCoin(), productPageVo.getAlgorithm(), shopId);
PageInfo<ProductDto> pageInfo = new PageInfo<>(leaseProducts);
if(leaseProducts.isEmpty()){
//, "不存在出售商品"
return PageResult.success(new ArrayList<>());
}
//获取店铺对应的支付方式
List<Long> shopIds = leaseProducts.stream().map(ProductDto::getShopId).distinct().collect(Collectors.toList());
List<PayTypeDto> payType = leaseShopConfigMapper.getPayType(shopIds);
Map<Long, List<PayTypeDto>> payTypeMap = payType.stream().collect(Collectors.groupingBy(PayTypeDto::getShopId));
//配置支付列表
for (ProductDto productDto : leaseProducts) {
productDto.setPayTypes(payTypeMap.get(productDto.getShopId()));
}
PageResult<ProductDto> success = PageResult.success(leaseProducts);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
@Override
public Result<ProductDto> getMachineInfoById(BaseVo baseVo) {
LeaseProduct leaseProduct = leaseProductMapper.selectById(baseVo.getId());
if (leaseProduct == null) {
//"商品不存在"
return Result.success(null);
}
String priceRange = leaseProduct.getMinPrice().equals(leaseProduct.getMaxPrice()) ? leaseProduct.getMinPrice().toString(): leaseProduct.getMinPrice() +"-"+leaseProduct.getMaxPrice();
ProductDto productDto = ProductDto.builder()
.id(leaseProduct.getId())
.shopId(leaseProduct.getShopId())
.name(leaseProduct.getName())
.image(leaseProduct.getImage())
.type(leaseProduct.getType())
.state(leaseProduct.getState())
.priceRange(priceRange)
.description(leaseProduct.getDescription())
.coin(leaseProduct.getCoin())
.algorithm(leaseProduct.getAlgorithm())
.build();
return Result.success(productDto);
}
@Override
public PageResult<ProductMachineDto> getProductMachineInfo(ProductMachineVo productMachineVo) {
Long productId = productMachineVo.getId();
LeaseProduct product = getById(productId);
List<PayConfigDto> shopWalletInfo = leaseShopMapper.getShopWalletInfo(product.getShopId());
PageHelper.startPage(productMachineVo.getPageNum(), productMachineVo.getPageSize());
productMachineVo = buildQuery(productMachineVo,shopWalletInfo.get(0));
List<ProductMachineDto> productMachineDtoList = leaseProductMachineMapper.getMachinesByPriceAndPowerAndDissipation(productMachineVo, product.getCoin());
PageInfo<ProductMachineDto> pageInfo = new PageInfo<>(productMachineDtoList);
if (productMachineDtoList.isEmpty()){
//,"不存在矿机"
return PageResult.success(new ArrayList<>());
}
//币价 单位usdt
BigDecimal price = redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(product.getCoin())) == null ? BigDecimal.ZERO : redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(product.getCoin()));
//报块奖励
BigDecimal reward =redisService.getCacheBigDecimal(RedisCoinInfoKey.getRewardKey(product.getCoin())) == null ? BigDecimal.ZERO : redisService.getCacheBigDecimal(RedisCoinInfoKey.getRewardKey(product.getCoin())) ;
//全网算力单位是MH/s
BigDecimal mhs = redisService.getCacheBigDecimal(RedisCoinInfoKey.getMhsKey(product.getCoin())) == null ? BigDecimal.ZERO : redisService.getCacheBigDecimal(RedisCoinInfoKey.getMhsKey(product.getCoin()));
List<ProductMachineDto> productMachines = productMachineDtoList.stream()
.peek(productMachineDto -> {
//理论收益
BigDecimal singleTheoryMachineIncome = BigDecimal.ZERO;
productMachineDto.setAlgorithm(product.getAlgorithm());
// 矿机算力单位转换 + 计算单矿机平均算力(ComputingPower coin_real_power 24小时总算力)
BigDecimal computingPower = PowerUnitUtils.getPower(productMachineDto.getUnit(), productMachineDto.getComputingPower()
.multiply(BigDecimal.valueOf(1000 * 1000)));
//全网算力单位转换
BigDecimal power = PowerUnitUtils.getPower(productMachineDto.getUnit(), mhs.multiply(BigDecimal.valueOf(1000 * 1000)));
//(理论收益 = 矿机算力/全网算力 * 24h /出块间隔秒数 * 单块奖励redis中nexa:reward
singleTheoryMachineIncome = computingPower.divide( power,6, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(24 * 60 * 60)
.divide(BlockInterval.getBlockCountByCoinName(product.getCoin()), 6, RoundingMode.HALF_UP))
.multiply(reward);
productMachineDto.setComputingPower(computingPower);
productMachineDto.setTheoryIncome(singleTheoryMachineIncome);
productMachineDto.setTheoryUsdtIncome(singleTheoryMachineIncome.multiply(price));
})
.collect(Collectors.toList());
//分页内排序
productMachines = sorted(productMachines,productMachineVo);
PageResult<ProductMachineDto> success = PageResult.success(productMachines);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
/**
* 构建查询条件
* @param productMachineVo
* @param payConfigDto
* @return
*/
public ProductMachineVo buildQuery(ProductMachineVo productMachineVo,PayConfigDto payConfigDto){
if (StringUtils.isEmpty(productMachineVo.getChain()) && StringUtils.isEmpty(productMachineVo.getCoin())){
productMachineVo.setChain(payConfigDto.getPayChain());
productMachineVo.setCoin(payConfigDto.getPayCoin());
}
BigDecimal power = PowerUnit.getPower(productMachineVo.getUnit()).divide(BigDecimal.valueOf(1000 * 1000),2,RoundingMode.HALF_UP);
productMachineVo.setMaxPower(productMachineVo.getMaxPower().multiply(power));
productMachineVo.setMinPower(productMachineVo.getMinPower().multiply(power));
//算力设置
if (productMachineVo.getMaxPower().compareTo(productMachineVo.getMinPower()) < 0){
productMachineVo.setMaxPower(productMachineVo.getMinPower());
productMachineVo.setMinPower(productMachineVo.getMaxPower());
}
//功耗设置
if (productMachineVo.getMaxPowerDissipation().compareTo(productMachineVo.getMinPowerDissipation()) < 0){
productMachineVo.setMaxPowerDissipation(productMachineVo.getMinPowerDissipation());
productMachineVo.setMinPowerDissipation(productMachineVo.getMaxPowerDissipation());
}
//价格设置
if (productMachineVo.getMaxPrice().compareTo(productMachineVo.getMinPrice()) < 0){
productMachineVo.setMaxPrice(productMachineVo.getMinPrice());
productMachineVo.setMinPrice(productMachineVo.getMaxPrice());
}
System.out.println("请求参数"+ JSONUtil.toJsonPrettyStr(productMachineVo));
return productMachineVo;
}
public List<ProductMachineDto> sorted(List<ProductMachineDto> productMachineDtoList,ProductMachineVo productMachineVo){
if (productMachineVo.getPriceSort() != null) {
Comparator<ProductMachineDto> priceComparator = productMachineVo.getPriceSort() ?
Comparator.comparing(ProductMachineDto::getPrice) :
Comparator.comparing(ProductMachineDto::getPrice).reversed();
return productMachineDtoList.stream()
.sorted(priceComparator)
.collect(Collectors.toList());
} else if (productMachineVo.getPowerSort() != null) {
Comparator<ProductMachineDto> powerComparator = productMachineVo.getPowerSort() ?
Comparator.comparing(ProductMachineDto::getComputingPower) :
Comparator.comparing(ProductMachineDto::getComputingPower).reversed();
return productMachineDtoList.stream()
.sorted(powerComparator)
.collect(Collectors.toList());
} else if (productMachineVo.getPowerDissipationSort() != null) {
Comparator<ProductMachineDto> powerDissipationComparator = productMachineVo.getPowerDissipationSort() ?
Comparator.comparing(ProductMachineDto::getPowerDissipation) :
Comparator.comparing(ProductMachineDto::getPowerDissipation).reversed();
return productMachineDtoList.stream()
.sorted(powerDissipationComparator)
.collect(Collectors.toList());
} else {
return productMachineDtoList;
}
}
@Override
public Result<List<PayConfigDto>> getPayTypes(ShopPayTypeVo shopPayTypeVo) {
Long shopId ;
if (shopPayTypeVo == null){
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.select(LeaseShop::getId)
.eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
.eq(LeaseShop::getDel, false));
if (leaseShop == null){
//"店铺不存在"
return Result.success(null);
}
shopId = leaseShop.getId();
}else{
shopId = shopPayTypeVo.getShopId();
}
List<PayConfigDto> shopWalletInfo = leaseShopMapper.getShopWalletInfo(shopId);
return Result.success(shopWalletInfo);
}
///**
// * 计算每个价格分组中商品机器的功耗、理论算力、实际算力范围,并返回对应的范围信息对象
// * @param productMachineDtoMap 按价格分组的商品机器列表
// * @return 每个价格对应的商品机器范围信息
// */
//public static Map<BigDecimal, ProductMachineRangeGroupDto> calculateRanges(Map<BigDecimal, List<ProductMachineDto>> productMachineDtoMap) {
// // 使用 AtomicInteger 来实现 onlyKey 递增
// AtomicInteger onlyKey = new AtomicInteger(0);
// return productMachineDtoMap.entrySet().stream()
// .collect(Collectors.toMap(
// Map.Entry::getKey,
// entry -> {
// List<ProductMachineDto> productMachines = entry.getValue();
// int number = productMachines.size();
// BigDecimal price = entry.getKey();
//
// // 计算功耗范围
// BigDecimal minPower = productMachines.stream()
// .map(ProductMachineDto::getPowerDissipation)
// .min(BigDecimal::compareTo)
// .orElse(BigDecimal.ZERO);
// BigDecimal maxPower = productMachines.stream()
// .map(ProductMachineDto::getPowerDissipation)
// .max(BigDecimal::compareTo)
// .orElse(BigDecimal.ZERO);
// String powerRange = minPower.equals(maxPower) ? String.valueOf(minPower) : minPower + " - " + maxPower;
//
// // 计算理论算力范围
// BigDecimal minTheoryPower = productMachines.stream()
// .map(ProductMachineDto::getTheoryPower)
// .min(BigDecimal::compareTo)
// .orElse(BigDecimal.ZERO);
// BigDecimal maxTheoryPower = productMachines.stream()
// .map(ProductMachineDto::getTheoryPower)
// .max(BigDecimal::compareTo)
// .orElse(BigDecimal.ZERO);
// String theoryPowerRange = minTheoryPower.equals(maxTheoryPower) ? String.valueOf(minTheoryPower) : minTheoryPower + " - " + maxTheoryPower;
//
// // 计算实际算力范围
// BigDecimal minComputingPower = productMachines.stream()
// .map(ProductMachineDto::getComputingPower)
// .min(BigDecimal::compareTo)
// .orElse(BigDecimal.ZERO);
// BigDecimal maxComputingPower = productMachines.stream()
// .map(ProductMachineDto::getComputingPower)
// .max(BigDecimal::compareTo)
// .orElse(BigDecimal.ZERO);
// String computingPowerRange = minComputingPower.equals(maxComputingPower) ? String.valueOf(minComputingPower) : minComputingPower + " - " + maxComputingPower;
// String unit = productMachines.get(0).getUnit();
// int onlyKey1 = onlyKey.incrementAndGet();
// return ProductMachineRangeGroupDto.builder()
// .onlyKey(onlyKey1)
// .powerRange(powerRange)
// .theoryPowerRange(theoryPowerRange)
// .computingPowerRange(computingPowerRange)
// .number(number)
// .price(price)
// .unit(unit)
// .build();
// }
// ));
//}
@Override
public Result<String> addProduct(ProductURDVo productURDVo) {
//校验是否存在收款钱包,不存在无法创建商品
List<LeaseShopConfig> leaseShopConfig = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getShopId, productURDVo.getShopId()).eq(LeaseShopConfig::getDel, 0));
if (leaseShopConfig.isEmpty()){
return Result.fail("添加商品失败,请先绑定收款钱包");
}
String algorithm = Algorithm.getAlgorithm(productURDVo.getCoin());
String coinFullName = Algorithm.getCoinFullName(productURDVo.getCoin());
LeaseProduct product = LeaseProduct.builder()
.image(productURDVo.getImage())
.name(productURDVo.getName())
.algorithm(algorithm)
.description(productURDVo.getDescription())
.state(productURDVo.getState())
.type(productURDVo.getType())
.coin(productURDVo.getCoin())
.shopId(productURDVo.getShopId())
.coinFullName(coinFullName)
.build();
boolean save = save(product);
if (!save){
return Result.fail("新增商品失败");
}
return Result.success("新增商品成功");
}
@Override
@Transactional
public Result<String> updateProduct(ProductURDVo productURDVo) {;
PriceDto priceDto = leaseProductMachineMapper.getPriceRange(productURDVo.getId());
BigDecimal maxPrice = BigDecimal.ZERO;
BigDecimal minPrice = BigDecimal.ZERO;
if (priceDto != null){
maxPrice = priceDto.getPriceMax();
minPrice = priceDto.getPriceMin();
}
//校验商品是否能够上下架
if (productURDVo.getState() == 1 && leaseProductMachineMapper.checkHasSaleMachineByProductId(productURDVo.getId()) >= 1){
return Result.fail("商品下架失败,商品存在租约中矿机");
}
//修改商品主表
String algorithm = Algorithm.getAlgorithm(productURDVo.getCoin());
String coinFullName = Algorithm.getCoinFullName(productURDVo.getCoin());
LeaseProduct product = LeaseProduct.builder()
.id(productURDVo.getId())
.image(productURDVo.getImage())
.name(productURDVo.getName())
.description(productURDVo.getDescription())
.state(productURDVo.getState())
.algorithm(algorithm)
.maxPrice(maxPrice)
.minPrice(minPrice)
.type(productURDVo.getType())
.coinFullName(coinFullName)
.build();
boolean b1 = updateById(product);
if (b1){
return Result.success("修改商品成功");
}
return Result.fail("修改商品失败");
}
@Override
@Transactional
public Result<String> deleteProduct(Long id) {
int i = leaseProductMachineMapper.checkHasSaleMachineByProductId(id);
if(i >= 1){
return Result.fail("删除失败,该商品存在租约中的机器");
}
boolean updateFather = updateById(LeaseProduct.builder().id(id).del(true).build());
List<Long> machineIds = leaseProductMachineMapper.getIdsForProductId(id);
if (updateFather){
if (!machineIds.isEmpty()){
leaseProductMachineMapper.update(LeaseProductMachine.builder().del(true).build(),
new LambdaQueryWrapper<LeaseProductMachine>().in(LeaseProductMachine::getId, machineIds));
//删除矿机对应的售价
leaseProductMachinePriceService.update(LeaseProductMachinePrice.builder().del(true).build(),new LambdaUpdateWrapper<LeaseProductMachinePrice>().in(LeaseProductMachinePrice::getProductMachineId, machineIds));
}
return Result.success("删除成功");
}
return Result.fail("删除失败");
}
@Override
public Result<List<PayTypeDto>> getSupportPayType() {
Long shopId = getShopIdByProductId();
List<PayTypeDto> supportPayType = leaseProductMapper.getSupportPayType(shopId);
return Result.success(supportPayType);
}
@Override
public Result<List<ProductForWalletConfigDto>> getProductListForShopWalletConfig() {
Long shopId = getShopIdByProductId();
//1.获取商品列表
List<ProductForWalletConfigDto> productForShopWalletConfigDtoList = leaseProductMapper.getProductListForShopWalletConfig(shopId);
if (productForShopWalletConfigDtoList.isEmpty()){
return Result.success(productForShopWalletConfigDtoList);
}
//2.获取商品对应矿机
List<ProductMachineForWalletConfigDto> productMachineForWalletConfigDtoList = leaseProductMachineMapper.getProductListForShopWalletConfig(shopId);
BigDecimal usdtPrice = redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(productForShopWalletConfigDtoList.get(0).getCoin()));
Map<Long, List<ProductMachineForWalletConfigDto>> collect = productMachineForWalletConfigDtoList.stream()
.peek(productMachineForWalletConfigDto -> {
productMachineForWalletConfigDto.setTheoryUsdtIncome(productMachineForWalletConfigDto.getTheoryIncome()
.multiply(usdtPrice));
})
.collect(Collectors.groupingBy(ProductMachineForWalletConfigDto::getProductId));
for (ProductForWalletConfigDto productForWalletConfigDto : productForShopWalletConfigDtoList) {
List<ProductMachineForWalletConfigDto> list = collect.get(productForWalletConfigDto.getProductId());
if (list.isEmpty()){
productForShopWalletConfigDtoList.remove(productForWalletConfigDto);
}
productForWalletConfigDto.setMachineList(list);
}
return Result.success(productForShopWalletConfigDtoList);
}
public Long getShopIdByProductId(){
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.select(LeaseShop::getId)
.eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
.eq(LeaseShop::getDel, false));
return leaseShop.getId();
}
@Override
@Transactional
public Result<String> updateProductListForShopWalletConfig(ProductMachineForWalletConfigVo productMachineForWalletConfigVo) {
List<String> payCoinsList = new ArrayList<>(Arrays.asList(productMachineForWalletConfigVo.getSymbol().split(",")));
String chain = productMachineForWalletConfigVo.getChain();
String address = productMachineForWalletConfigVo.getPayAddress();
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.eq(LeaseShop::getAuthId, SecurityUtils.getUserId()));
boolean check = checkHashWalletInfo(leaseShop.getId(),chain,address, payCoinsList);
if (!check){
return Result.fail("绑定钱包失败,钱包格式不正确或该链和币种钱包已绑定过");
}
String[] symbolList = productMachineForWalletConfigVo.getSymbol().split(",");
List<ProductMachineForWalletConfigVo.PriceVo> priceAndIdList = productMachineForWalletConfigVo.getProductMachineForWalletConfigVoList();
List<LeaseProductMachinePrice> leaseProductMachinePriceList = new ArrayList<>();
for (ProductMachineForWalletConfigVo.PriceVo priceVo : priceAndIdList) {
String[] priceList = priceVo.getPrice().split(",");
if (priceList.length != symbolList.length){
return Result.fail("绑定钱包失败,存在商品矿机未设置新钱包售价");
}
for (int i = 0; i < priceList.length; i++) {
leaseProductMachinePriceList.add(LeaseProductMachinePrice.builder()
.productMachineId(priceVo.getProductMachineId())
.price(new BigDecimal(priceList[i]))
.coin(symbolList[i])
.chain(chain)
.build());
}
}
boolean b = leaseProductMachinePriceService.saveBatch(leaseProductMachinePriceList);
if (b || leaseProductMachinePriceList.isEmpty()){
//绑定钱包新钱包
List<LeaseShopConfig> shopConfigList = leaseShopConfigMapper.getCoinIconByChainAndCoin(chain, payCoinsList);
String qrCode = QrCodeUtils.creatRrCode(address, 200, 200);
for (LeaseShopConfig leaseShopConfig : shopConfigList) {
leaseShopConfig.setShopId(leaseShop.getId());
leaseShopConfig.setChain(chain);
leaseShopConfig.setPayAddress(address);
leaseShopConfig.setQrcode(qrCode);
}
boolean insetWallet = leaseShopConfigService.saveBatch(shopConfigList);
if (insetWallet){
return Result.success("绑定钱包成功");
}
throw new ProductSoldOutException ("钱包绑定失败");
}
throw new ProductSoldOutException ("新币种钱包商品售价新增失败");
}
/**
* 钱包格式校验,以及判断该链和币种钱包是否已存在
* @param chain
* @param address
* @param coinList
* @return
*/
public boolean checkHashWalletInfo(Long shopId,String chain,String address,List<String> coinList){
if (!WalletRuleCheckUtils.checkAddress(chain,address)){
return false;
}
List<LeaseShopConfig> configList = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getShopId, shopId)
.eq(LeaseShopConfig::getChain, chain)
.in(LeaseShopConfig::getPayCoin, coinList)
.eq(LeaseShopConfig::getDel, false)
);
if (!configList.isEmpty()){
return false;
}
return true;
}
}

View File

@@ -0,0 +1,20 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseShopConfig;
import com.m2pool.lease.mapper.LeaseShopConfigMapper;
import com.m2pool.lease.service.LeaseShopConfigService;
import org.springframework.stereotype.Service;
/**
* <p>
* 店铺商品配置表 服务实现类
* </p>
*
* @author yyb
* @since 2025-08-05
*/
@Service
public class LeaseShopConfigServiceImpl extends ServiceImpl<LeaseShopConfigMapper, LeaseShopConfig> implements LeaseShopConfigService {
}

View File

@@ -0,0 +1,758 @@
package com.m2pool.lease.service.impl;
import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.lease.aspect.OperationLogAspect;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.dto.v2.PayWithdrawSellerRecordDto;
import com.m2pool.lease.dto.v2.ShopWalletInfoDto;
import com.m2pool.lease.entity.*;
import com.m2pool.lease.exception.MachineException;
import com.m2pool.lease.exception.PaymentException;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.mq.message.RabbitmqPayWithdrawMessage;
import com.m2pool.lease.service.LeaseShopConfigService;
import com.m2pool.lease.service.LeaseShopService;
import com.m2pool.lease.utils.*;
import com.m2pool.lease.vo.*;
import com.m2pool.lease.vo.v2.ShopWalletInfoVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.m2pool.lease.constant.CoinCharge.getChargeByChainAndCoin;
import static com.m2pool.lease.constant.RabbitmqConstant.PAY_WITHDRAW_QUEUE;
/**
* <p>
* 店铺表 服务实现类
* </p>
*
* @author yyb
* @since 2025-08-05
*/
@Service
public class LeaseShopServiceImpl extends ServiceImpl<LeaseShopMapper, LeaseShop> implements LeaseShopService {
@Resource
private LeaseShopMapper leaseShopMapper;
@Resource
private LeaseShopConfigMapper leaseShopConfigMapper;
@Resource
private LeaseOrderItemMapper leaseOrderItemMapper;
@Resource
private LeaseShopConfigService leaseShopConfigService;
@Resource
private LeaseProductMapper leaseProductMapper;
@Resource
private LeaseProductMachineMapper leaseProductMachineMapper;
@Resource
private LeaseMachinePriceMapper leaseMachinePriceMapper;
@Resource
private LeaseUserMapper leaseUserMapper;
@Resource
private LeasePayWithdrawMessageMapper leasePayWithdrawMessageMapper;
@Resource
private RabbitTemplate rabbitTemplate;
@Resource
private LeaseAutoAddressMapper leaseAutoAddressMapper;
@Resource
private LeaseMachineMapper leaseMachineMapper;
@Resource
private LeaseMachineConfigMapper leaseMachineConfigMapper;
@Override
public Result<String> addShop(ShopVo shopVo) {
LeaseShop leaseShop1 = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()).eq(LeaseShop::getDel, false));
LeaseShop leaseShop = LeaseShop.builder()
.userEmail(SecurityUtils.getUsername())
.name(shopVo.getName())
.image(shopVo.getImage())
.description(shopVo.getDescription())
.state(shopVo.getState())
.feeRate(shopVo.getFeeRate())
.authId(SecurityUtils.getUserId())
.build();
if(leaseShop1 != null){
return Result.fail("当前已存在店铺,请勿重复添加");
}
boolean save = save(leaseShop);
return save ? Result.success("新增店铺成功") : Result.fail("新增店铺失败");
}
@Override
public Result<String> updateShop(ShopVo shopVo) {
if (shopVo.getId() == null || shopVo.getId() == 0){
return Result.fail("id不能为空或0");
}
LeaseShop leaseShop = LeaseShop.builder()
.id(shopVo.getId())
.userEmail(SecurityUtils.getUsername())
.name(shopVo.getName())
.image(shopVo.getImage())
.description(shopVo.getDescription())
.state(shopVo.getState())
.feeRate(shopVo.getFeeRate())
.authId(SecurityUtils.getUserId())
.build();
LeaseShop byId = getById(shopVo.getId());
if (byId.getDel()){
return Result.fail("修改失败,店铺已被删除");
}
boolean save = updateById(leaseShop);
if (save) {
return Result.success("修改店铺成功");
}
return Result.fail("修改店铺失败");
}
@Override
public Result<String> closeShop(BaseVo baseVo) {
LeaseShop leaseShop = getById(baseVo.getId());
if (leaseShop == null) {
return Result.fail("店铺不存在");
}
//校验是否存在已售出的矿机
if (leaseProductMachineMapper.checkHasSaleMachineByShopId(baseVo.getId()) >= 1 || leaseMachineMapper.checkHasSaleMachineByShopId(baseVo.getId()) >= 1){
return Result.fail("关闭店铺失败,店铺存在租约中矿机");
}
if (leaseShop.getState() == 1){
leaseShop.setState(2);
boolean b = updateById(leaseShop);
return b ? Result.success("关闭店铺成功") : Result.fail("关闭店铺失败");
}
if (leaseShop.getState() == 2){
leaseShop.setState(1);
boolean b = updateById(leaseShop);
return b ? Result.success("开启店铺成功") : Result.fail("开启店铺失败");
}
return Result.fail("店铺正在审核中不能开启和关闭店铺");
}
@Override
public Result<ShopDto> getShopByUserEmail() {
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
.eq(LeaseShop::getDel, false));
ShopDto build = null;
if (leaseShop != null){
build = ShopDto.builder()
.id(leaseShop.getId())
.name(leaseShop.getName())
.image(leaseShop.getImage())
.feeRate(leaseShop.getFeeRate())
.description(leaseShop.getDescription())
.state(leaseShop.getState())
.del(leaseShop.getDel())
.build();
}
return Result.success(build);
}
@Override
public Result<ShopDto> getShopById(BaseVo baseVo) {
LeaseShop leaseShop = leaseShopMapper.selectById(baseVo.getId());
ShopDto build = null;
if (leaseShop != null && !leaseShop.getDel()){
build = ShopDto.builder()
.id(leaseShop.getId())
.name(leaseShop.getName())
.image(leaseShop.getImage())
.description(leaseShop.getDescription())
.state(leaseShop.getState())
.feeRate(leaseShop.getFeeRate())
.del(leaseShop.getDel())
.build();
}
return Result.success(build);
}
@Override
@Transactional
public Result<String> deleteShop(BaseVo baseVo) {
LeaseShop byId = getById(baseVo.getId());
if (byId.getDel()){
return Result.fail("删除店铺失败,店铺已删除,请刷新页面");
}
updateMachineInfoV1(baseVo.getId());
updateMachineInfoV2(baseVo.getId());
boolean b = updateById(LeaseShop.builder().id(baseVo.getId()).del(true).build());
if (b){
return Result.success("删除成功");
}
return Result.fail("删除失败");
}
/**
* 删除店铺时,将店铺下所有矿机和对应钱包删除 V1版本
*
* */
public void updateMachineInfoV1(Long shopId){
//校验是否存在已售出的矿机
if (leaseProductMachineMapper.checkHasSaleMachineByShopId(shopId) >= 1){
throw new MachineException("注销失败,店铺存在租约中矿机");
}
leaseProductMapper.update(LeaseProduct.builder().del(true).build(), new LambdaUpdateWrapper<LeaseProduct>()
.eq(LeaseProduct::getShopId, shopId));
leaseProductMachineMapper.update(LeaseProductMachine.builder().del(true).build(), new LambdaUpdateWrapper<LeaseProductMachine>()
.eq(LeaseProductMachine::getShopId, shopId));
}
/**
* 删除店铺时,将店铺下所有矿机和对应钱包删除 V2版本
*
* */
public void updateMachineInfoV2(Long shopId){
//校验是否存在已售出的矿机
if (leaseMachineMapper.checkHasSaleMachineByShopId(shopId) >= 1){
throw new MachineException("注销失败,店铺存在租约中矿机");
}
//校验是否存在余额不为0的钱包
List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
.select(LeaseShopConfig::getId,LeaseShopConfig::getBalance)
.eq(LeaseShopConfig::getShopId, shopId).eq(LeaseShopConfig::getDel, false));
if (leaseShopConfigs.stream().anyMatch(leaseShopConfig -> leaseShopConfig.getBalance().compareTo(BigDecimal.ZERO) > 0)){
throw new MachineException("注销失败,店铺存在余额不为0的钱包");
}
leaseMachineMapper.update(LeaseMachine.builder().del(true).build(), new LambdaUpdateWrapper<LeaseMachine>()
.eq(LeaseMachine::getShopId, shopId));
List<Long> ids = leaseMachineMapper.selectList(new LambdaQueryWrapper<LeaseMachine>()
.select(LeaseMachine::getId)
.eq(LeaseMachine::getShopId, shopId))
.stream().map(LeaseMachine::getId)
.collect(Collectors.toList());
if (!ids.isEmpty()){
leaseMachineConfigMapper.delete(new LambdaQueryWrapper<LeaseMachineConfig>().in(LeaseMachineConfig::getMachineId, ids));
}
leaseShopConfigMapper.update(LeaseShopConfig.builder().del(true).build(), new LambdaUpdateWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getShopId, shopId));
}
@Override
public Result<List<ShopNameDto>> getProductListById(BaseVo baseVo) {
List<LeaseProduct> leaseProducts = leaseProductMapper.selectList(new LambdaQueryWrapper<LeaseProduct>().eq(LeaseProduct::getShopId, baseVo.getId()).eq(LeaseProduct::getDel, false));
List<ShopNameDto> collect = leaseProducts.stream().map(leaseProduct ->
ShopNameDto.builder()
.id(leaseProduct.getId())
.name(leaseProduct.getName()).build()
).collect(Collectors.toList());
return Result.success(collect);
}
@Override
public Result<List<ShopConfigDto>> getShopConfig(BaseVo baseVo) {
List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getShopId, baseVo.getId())
.eq(LeaseShopConfig::getDel, false));
if (leaseShopConfigs.isEmpty()){
//店铺还未设置钱包
return Result.success(null);
}
Map<String, List<LeaseShopConfig>> collect = leaseShopConfigs.stream().collect(Collectors.groupingBy(LeaseShopConfig::getChain));
List<ShopConfigDto> shopConfigDtos = new ArrayList<>();
collect.forEach((chain, list) -> {
LeaseShopConfig leaseShopConfig = list.get(0);
List<ShopConfigDto.CoinDto> coinDtoList = list.stream().map(shopConfig -> {
ShopConfigDto.CoinDto coinDto = new ShopConfigDto.CoinDto();
coinDto.setPayCoin(shopConfig.getPayCoin());
coinDto.setImage(shopConfig.getPayCoinImage());
return coinDto;
}).collect(Collectors.toList());
ShopConfigDto build = ShopConfigDto.builder()
.shopId(leaseShopConfig.getShopId())
.chain(leaseShopConfig.getChain())
.payType(leaseShopConfig.getPayType())
.payAddress(leaseShopConfig.getPayAddress())
.children(coinDtoList)
.build();
build.setId(leaseShopConfig.getId());
shopConfigDtos.add( build);
});
return Result.success(shopConfigDtos);
}
@Override
public Result<String> addShopConfig(ShopConfigVo shopConfigVo) {
if (checkSystemctlAddress(shopConfigVo.getPayAddress(), shopConfigVo.getChain())){
return Result.fail("收款钱包不能使用系统钱包");
}
//钱包地址校验
if (!WalletRuleCheckUtils.checkAddress(shopConfigVo.getChain(),shopConfigVo.getPayAddress())){
return Result.fail("钱包地址格式错误");
}
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()));
List<String> payCoinsList = new ArrayList<>(Arrays.asList(shopConfigVo.getPayCoin().split(",")));
LeaseShopConfig configList = leaseShopConfigMapper.selectOne(new LambdaQueryWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getPayAddress, shopConfigVo.getPayAddress())
.eq(LeaseShopConfig::getPayCoin, shopConfigVo.getPayCoin())
.eq(LeaseShopConfig::getChain, shopConfigVo.getChain())
.eq(LeaseShopConfig::getDel, false)
);
if (configList != null){
return Result.fail("绑定"+shopConfigVo.getPayAddress()+"钱包失败!" + shopConfigVo.getChain()+""+ shopConfigVo.getPayCoin()+ "币种钱包,已被绑定");
}
//获取币种图标
List<LeaseShopConfig> shopConfigList = leaseShopConfigMapper.getCoinIconByChainAndCoin(shopConfigVo.getChain(), payCoinsList);
String payAddress = shopConfigVo.getPayAddress();
String qrCode = QrCodeUtils.creatRrCode(payAddress, 200, 200);
for (LeaseShopConfig leaseShopConfig : shopConfigList) {
leaseShopConfig.setShopId(leaseShop.getId());
leaseShopConfig.setPayType(shopConfigVo.getPayType());
leaseShopConfig.setChain(shopConfigVo.getChain());
leaseShopConfig.setPayAddress(payAddress);
leaseShopConfig.setQrcode(qrCode);
}
boolean b = leaseShopConfigService.saveBatch(shopConfigList);
if (b){
return Result.success("添加成功");
}
return Result.fail("添加失败");
}
@Override
public Result<String> updateShopConfig(ShopConfigVo shopConfigVo) {
if (checkSystemctlAddress(shopConfigVo.getPayAddress(), shopConfigVo.getChain())){
return Result.fail("收款钱包不能使用系统钱包");
}
if ( !WalletRuleCheckUtils.checkAddress(shopConfigVo.getChain(),shopConfigVo.getPayAddress())){
return Result.fail("提现地址格式不符合"+shopConfigVo.getChain()+"节点");
}
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>().eq(LeaseShop::getUserEmail, SecurityUtils.getUsername()));
List<String> payCoinsList = new ArrayList<>(Arrays.asList(shopConfigVo.getPayCoin().split(",")));
String payAddress = shopConfigVo.getPayAddress();
String qrCode = QrCodeUtils.creatRrCode(payAddress, 200, 200);
List<LeaseShopConfig> configList = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getShopId, leaseShop.getId())
.eq(LeaseShopConfig::getChain, shopConfigVo.getChain())
.eq(LeaseShopConfig::getDel, false)
);
//比较已绑定币种 和 本次修改币种的差异
List<LeaseShopConfig> insertOrUpdateList = new ArrayList<>();
List<LeaseShopConfig> deleteList = new ArrayList<>();
for (LeaseShopConfig leaseShopConfig : configList) {
if(!payCoinsList.contains(leaseShopConfig.getPayCoin())){
leaseShopConfig.setDel( true);
deleteList.add(leaseShopConfig);
}else if (shopConfigVo.getPayAddress().equalsIgnoreCase(leaseShopConfig.getPayAddress())){
insertOrUpdateList.add(LeaseShopConfig.builder()
.id(leaseShopConfig.getId())
.shopId(leaseShop.getId())
.payType(shopConfigVo.getPayType())
.chain(shopConfigVo.getChain())
.qrcode(qrCode)
.payCoin(leaseShopConfig.getPayCoin())
.payAddress(payAddress)
.build());
}else{
//如果修改了地址 那么就是新增一个 旧的删除
insertOrUpdateList.add(LeaseShopConfig.builder()
.shopId(leaseShop.getId())
.payType(shopConfigVo.getPayType())
.chain(shopConfigVo.getChain())
.qrcode(qrCode)
.payCoin(leaseShopConfig.getPayCoin())
.payAddress(payAddress)
.build());
leaseShopConfig.setDel( true);
deleteList.add(leaseShopConfig);
}
}
List<String> alreadyExistCoinList = configList.stream().map(LeaseShopConfig::getPayCoin).collect(Collectors.toList());
for (String coin : payCoinsList) {
//不存在新增
if (!alreadyExistCoinList.contains(coin)){
insertOrUpdateList.add(LeaseShopConfig.builder()
.shopId(leaseShop.getId())
.payCoin(coin)
.payType(shopConfigVo.getPayType())
.chain(shopConfigVo.getChain())
.qrcode(qrCode)
.payAddress(payAddress)
.build());
}
}
if (!deleteList.isEmpty()){
boolean delete = leaseShopConfigService.updateBatchById(deleteList);
}
List<String> coinList = insertOrUpdateList.stream().map(LeaseShopConfig::getPayCoin).collect(Collectors.toList());
//获取币种对应的图片
List<LeaseShopConfig> coinIconByChainAndCoin = leaseShopConfigMapper.getCoinIconByChainAndCoin(shopConfigVo.getChain(), coinList);
for (LeaseShopConfig leaseShopConfig : insertOrUpdateList) {
for (LeaseShopConfig configImage : coinIconByChainAndCoin) {
if (leaseShopConfig.getPayCoin().equals(configImage.getPayCoin())){
leaseShopConfig.setPayCoinImage(configImage.getPayCoinImage());
}
}
}
boolean save = leaseShopConfigService.saveOrUpdateBatch(insertOrUpdateList);
if (save){
return Result.success("修改成功");
}
return Result.fail("修改失败");
}
/**
* 校验卖家收款钱包是否为本系统钱包
* @param address
* @param chain
* @return
*/
public boolean checkSystemctlAddress(String address, String chain){
LeaseAutoAddress leaseAutoAddress = leaseAutoAddressMapper.selectOne(new LambdaQueryWrapper<LeaseAutoAddress>()
.eq(LeaseAutoAddress::getAddress, address)
.eq(LeaseAutoAddress::getFromChain, chain));
if (leaseAutoAddress != null){
return true;
}
return false;
}
@Override
public Result<String> deleteShopConfig(BaseVo baseVo) {
//1.根据id找到要删除的钱包配置
LeaseShopConfig config = leaseShopConfigMapper.selectById(baseVo.getId());
if (config.getBalance().compareTo(BigDecimal.ZERO) > 0){
return Result.fail("删除失败,钱包余额不为0");
}
//2.校验当前用户还有几个卖家钱包
Long configNums = leaseShopConfigMapper.selectCount(new LambdaQueryWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getShopId, config.getShopId()).eq(LeaseShopConfig::getDel, false));
//3.获取当前用户店铺是否存在商品
//List<Long> ids = leaseProductMachineMapper.getIdsForShopId(config.getShopId());
//Long productNums = leaseProductMapper.selectCount(new LambdaQueryWrapper<LeaseProduct>()
// .eq(LeaseProduct::getShopId, config.getShopId())
// .eq(LeaseProduct::getDel, false));
List<LeaseMachine> leaseMachines = leaseMachineMapper.selectList(new LambdaQueryWrapper<LeaseMachine>()
.eq(LeaseMachine::getShopId, config.getShopId())
.eq(LeaseMachine::getDel, false)
);
List<Long> ids = leaseMachines.stream().map(LeaseMachine::getId).collect(Collectors.toList());
// 拥有的钱包数小于等于1 且 商品数不为0 不能删除
if (configNums <= 1 && !leaseMachines.isEmpty()){
return Result.fail("删除失败,店铺若存在商品,至少需要一个收款钱包");
}
//4.查询店铺中是否存在要删除链的钱包 的订单,存在订单不能删除
Long l = leaseOrderItemMapper.selectCount(new LambdaQueryWrapper<LeaseOrderItem>()
.eq(LeaseOrderItem::getChain, config.getChain())
.ne(LeaseOrderItem::getStatus, 0)
);
if (l > 0){
return Result.fail("删除钱包失败,该钱包存在交易中的订单");
}
config.setDel(true);
//5.删除配置
boolean b = leaseShopConfigService.updateById(config);
if (b ){
//6.删除所有矿机对应的价格配置
if (!ids.isEmpty()){
leaseMachinePriceMapper.update(LeaseMachinePrice.builder().del(true).build(),
new LambdaQueryWrapper<LeaseMachinePrice>()
.eq(LeaseMachinePrice::getChain, config.getChain())
.in(LeaseMachinePrice::getMachineId,ids)
);
}
return Result.success("删除成功");
}
return Result.fail("删除失败");
}
@Override
public Result<List<ChainListDto>> getChainAndList() {
//LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>().eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
// .eq(LeaseShop::getDel, false));
//获取本系统支持的所有链和币种
List<CoinFullDto> chainAndList = leaseShopConfigMapper.getChainAndList(null);
//获取卖家已绑定的币种
//List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
// .eq(LeaseShopConfig::getShopId, leaseShop.getId())
//);
//for (CoinFullDto coinFullDto : chainAndList) {
// for (LeaseShopConfig leaseShopConfig : leaseShopConfigs) {
// if (coinFullDto.getChainValue().equals(leaseShopConfig.getChain()) && coinFullDto.getCoinValue().equals(leaseShopConfig.getPayCoin())){
// coinFullDto.setHasBind(1);
// }
// }
//}
return Result.success(buildChainList(chainAndList));
}
@Override
public Result<List<ChainListDto>> getChainAndListForSeller(BaseVo baseVo) {
//LeaseShop leaseShop = leaseShopMapper.selectById(baseVo.getId());
if (baseVo.getId() == null){
return Result.fail("未检测到该店铺");
}
List<CoinFullDto> chainAndListForSeller = leaseShopConfigMapper.getChainAndListForSeller(baseVo.getId());
return Result.success(buildChainList(chainAndListForSeller));
}
@Override
public Result<ChainListDto> getChainAndCoin(BaseVo baseVo) {
LeaseShopConfig config = leaseShopConfigMapper.selectOne(new LambdaQueryWrapper<LeaseShopConfig>().eq(LeaseShopConfig::getId, baseVo.getId()));
if (config == null){
return Result.fail("未检测到该币种");
}
//商家链已绑定的币种
List<LeaseShopConfig> leaseShopConfigs = leaseShopConfigMapper.selectList(new LambdaQueryWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getChain, config.getChain())
.eq(LeaseShopConfig::getShopId, config.getShopId())
);
//获取本系统该链支持的所有币种
List<CoinFullDto> chainAndList = leaseShopConfigMapper.getChainAndList(config.getChain());
for (CoinFullDto coinFullDto : chainAndList) {
for (LeaseShopConfig leaseShopConfig : leaseShopConfigs) {
if (coinFullDto.getChainValue().equals(leaseShopConfig.getChain()) && coinFullDto.getCoinValue().equals(leaseShopConfig.getPayCoin())){
coinFullDto.setHasBind(1);
}
}
}
ChainListDto chainListDto = buildChainList(chainAndList).get(0);
chainListDto.setAddress(config.getPayAddress());
return Result.success(chainListDto);
}
private List<ChainListDto> buildChainList(List<CoinFullDto> chainAndList){
Map<String, List<CoinFullDto>> chainGroup = chainAndList.stream()
.collect(Collectors.groupingBy(CoinFullDto::getChainValue));
List<ChainListDto> result = new ArrayList<>();
for (Map.Entry<String, List<CoinFullDto>> entry : chainGroup.entrySet()) {
String chainValue = entry.getKey();
List<CoinFullDto> group = entry.getValue();
// 取第一个元素获取链标签
String chainLabel = group.get(0).getChainLabel();
List<ChainListDto.CoinListDto> coinList = group.stream()
.map(coinFullDto -> {
ChainListDto.CoinListDto coinDto = new ChainListDto.CoinListDto();
coinDto.setValue(coinFullDto.getCoinValue());
coinDto.setLabel(coinFullDto.getCoinLabel());
coinDto.setHasBind(coinFullDto.getHasBind());
return coinDto;
})
.collect(Collectors.toList());
ChainListDto chainListDto = ChainListDto.builder()
.value(chainValue)
.label(chainLabel)
.children(coinList)
.build();
result.add(chainListDto);
}
return result;
}
@Override
public Result<List<ShopWalletInfoDto>> getShopConfigV2(BaseVo baseVo) {
List<ShopWalletInfoDto> list = leaseShopConfigMapper.getShopWalletInfoList(baseVo.getId());
for (ShopWalletInfoDto shopWalletInfoDto : list) {
BigDecimal chargeByChainAndCoin = getChargeByChainAndCoin(shopWalletInfoDto.getChain(), shopWalletInfoDto.getPayCoin());
shopWalletInfoDto.setServiceCharge(chargeByChainAndCoin);
}
return Result.success(list);
}
@Override
public Result<String> withdrawBalanceForSeller(BalanceVo balanceVo) {
String username = SecurityUtils.getUsername();
Long authId = SecurityUtils.getUserId();
//校验地址
if (StringUtils.isEmpty(balanceVo.getToAddress()) || StringUtils.isEmpty(balanceVo.getToChain()) || StringUtils.isEmpty(balanceVo.getToSymbol()) ){
return Result.fail("提现地址,链,币种 不能为空");
}
if (!WalletRuleCheckUtils.checkAddress(balanceVo.getToChain(),balanceVo.getToAddress())){
return Result.fail("提现收款地址格式不正确");
}
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.select(LeaseShop::getId).eq(LeaseShop::getUserEmail, username).eq(LeaseShop::getDel, false));
ShopWalletInfoDto shopWalletInfo = leaseShopConfigMapper.getShopWalletInfo(leaseShop.getId(), balanceVo.getFromAddress(), balanceVo.getToChain(), balanceVo.getToSymbol());
if (shopWalletInfo == null || StringUtils.isEmpty(shopWalletInfo.getPayAddress())){
return Result.fail("提现地址不属于您,请登录正确的账号");
}
GoogleInfo googleInfo = leaseUserMapper.getGoogleInfoByEmail(username);
//开发环境
//if(googleInfo == null || StringUtils.isBlank(googleInfo.getSecret())){
// //未绑定定谷歌验证器
// return Result.fail("您的账号未开启双重验证,请先开启验证!");
//}
//if(!GoogleAuthenticator.checkCode(googleInfo.getSecret(), balanceVo.getCode(), System.currentTimeMillis())){
// return Result.fail("谷歌验证码错误");
//}
//同一个from只能存在一笔提现中的订单
Integer recentlyOneData = leasePayWithdrawMessageMapper.getRecentlyOneData(balanceVo.getFromAddress(), balanceVo.getToChain());
if (recentlyOneData != null && recentlyOneData == 2){
return Result.fail("提现申请失败,已存在一笔金额正在提现中...");
}
BigDecimal serviceCharge = getChargeByChainAndCoin(balanceVo.getToChain(), balanceVo.getToSymbol());
String queueId = UuidGeneratorUtil.generateUuidWithoutHyphen();
Long timestamp = System.currentTimeMillis()/1000;
//验证通过存储提现记录
int insert = leasePayWithdrawMessageMapper.insert(LeasePayWithdrawMessage.builder()
.queueId(queueId)
.shopId(leaseShop.getId())
.toChain(balanceVo.getToChain())
.toSymbol(balanceVo.getToSymbol())
.fromChain(shopWalletInfo.getChain())
.fromSymbol(shopWalletInfo.getPayCoin())
.fromAddress(shopWalletInfo.getPayAddress())
.serviceCharge(serviceCharge)
.toAddress(balanceVo.getToAddress())
.amount(balanceVo.getAmount())
.authId(authId)
.build());
LeaseShopConfig build = LeaseShopConfig.builder()
.id(shopWalletInfo.getId())
.balance(shopWalletInfo.getBalance())
.build();
int update = leaseShopConfigMapper.update(build,new LambdaUpdateWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getBalance, shopWalletInfo.getBalance()));
if (insert > 0 && update > 0){
//发送mq消息到队列
RabbitmqPayWithdrawMessage message = RabbitmqPayWithdrawMessage.builder()
.queue_id(queueId)
.from_address(shopWalletInfo.getPayAddress())
.to_address(balanceVo.getToAddress())
.amount(balanceVo.getAmount().subtract(serviceCharge))
.chain(balanceVo.getToChain())
.symbol(balanceVo.getToSymbol())
.fee(serviceCharge)
.timestamp(timestamp)
.sign(HashUtils.sha256(timestamp))
.user_email(username+"--"+authId)
.build();
try {
//发送提现消息
rabbitTemplate.convertAndSend(PAY_WITHDRAW_QUEUE,message);
OperationLogAspect.addExtraLogParam("手续费", serviceCharge.toString());
OperationLogAspect.addExtraLogParam("消息ID", queueId);
return Result.success("提现申请成功");
} catch (Exception e) {
throw new PaymentException("提现失败,失败原因"+e.getMessage());
}
}
throw new PaymentException("提现失败,余额已变化,请重新提现!");
}
@Override
public Result<String> updateShopConfigV2(ShopWalletInfoVo shopWalletInfoVo) {
String username = SecurityUtils.getUsername();
if ( !WalletRuleCheckUtils.checkAddress(shopWalletInfoVo.getChain(),shopWalletInfoVo.getPayAddress())){
return Result.fail("提现地址格式不符合"+shopWalletInfoVo.getChain()+"节点");
}
LeaseShopConfig byId = leaseShopConfigService.getById(shopWalletInfoVo.getId());
if (byId.getBalance().compareTo(BigDecimal.ZERO) > 0){
return Result.fail("钱包地址余额不为0,请先提现,否则会造成财产丢失");
}
//谷歌验证
GoogleInfo googleInfo = leaseUserMapper.getGoogleInfoByEmail(username);
//开发环境
//if(googleInfo == null || StringUtils.isBlank(googleInfo.getSecret())){
// //未绑定定谷歌验证器
// return Result.fail("您的账号未开启双重验证,请先开启验证!");
//}
//if(!GoogleAuthenticator.checkCode(googleInfo.getSecret(), balanceVo.getCode(), System.currentTimeMillis())){
// return Result.fail("谷歌验证码错误");
//}
LeaseShopConfig leaseShopConfig = leaseShopConfigMapper.selectOne(new LambdaQueryWrapper<LeaseShopConfig>()
.eq(LeaseShopConfig::getPayAddress, shopWalletInfoVo.getPayAddress())
.eq(LeaseShopConfig::getChain, shopWalletInfoVo.getChain())
.eq(LeaseShopConfig::getPayCoin, byId.getPayCoin())
.eq(LeaseShopConfig::getDel, false)
);
if (leaseShopConfig != null){
return Result.fail("修改失败,该钱包地址下链和币种已被绑定,请重新输入地址或先解绑后重新绑定");
}
boolean b = leaseShopConfigService.updateById(LeaseShopConfig.builder()
.id(shopWalletInfoVo.getId())
.payAddress(shopWalletInfoVo.getPayAddress())
.build());
if (b){
return Result.success("修改成功");
}
return Result.fail("修改失败");
}
@Override
public PageResult<PayWithdrawSellerRecordDto> balanceWithdrawList(PageVo pageVo) {
String userEmail = SecurityUtils.getUsername();
LeaseShop leaseShop = leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>()
.eq(LeaseShop::getUserEmail, userEmail).eq(LeaseShop::getDel, false));
if (leaseShop == null){
return PageResult.success(new ArrayList<>());
}
PageHelper.startPage(pageVo.getPageNum(), pageVo.getPageSize());
List<PayWithdrawSellerRecordDto> payWithdrawMessageDtoList = leasePayWithdrawMessageMapper.getSellerWithdrawRecord(leaseShop.getId());
PageInfo<PayWithdrawSellerRecordDto> pageInfo = new PageInfo<>(payWithdrawMessageDtoList);
PageResult<PayWithdrawSellerRecordDto> success = PageResult.success(payWithdrawMessageDtoList);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
}

View File

@@ -0,0 +1,542 @@
package com.m2pool.lease.service.impl;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.lease.constant.BlockInterval;
import com.m2pool.lease.constant.CoinCharge;
import com.m2pool.lease.redis.RedisCoinInfoKey;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.dto.v2.CartMachineInfoDto;
import com.m2pool.lease.dto.v2.ShopCartV2Dto;
import com.m2pool.lease.entity.*;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.redis.service.RedisService;
import com.m2pool.lease.service.LeaseShoppingCartInfoService;
import com.m2pool.lease.service.LeaseShoppingCartService;
import com.m2pool.lease.utils.PowerUnitUtils;
import com.m2pool.lease.utils.SecurityUtils;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.PageVo;
import com.m2pool.lease.vo.ProductAndMachineVo;
import com.m2pool.lease.vo.ShoppingCartInfoURDVo;
import com.m2pool.lease.vo.v2.AddGoodsVo;
import com.m2pool.lease.vo.v2.CartInfoVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <p>
* 购物车表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Service
public class LeaseShoppingCartServiceImpl extends ServiceImpl<LeaseShoppingCartMapper, LeaseShoppingCart> implements LeaseShoppingCartService {
@Resource
private LeaseShoppingCartInfoMapper leaseShoppingCartInfoMapper;
@Resource
private LeaseShoppingCartInfoService leaseShoppingCartInfoService;
@Resource
private LeaseProductMachineMapper leaseProductMachineMapper;
@Resource
private LeaseShopMapper leaseShopMapper;
@Resource
private LeaseProductMachinePriceMapper leaseProductMachinePriceMapper;
@Resource
private RedisService redisService;
@Resource
private LeaseMachineMapper leaseMachineMapper;
@Resource
private LeaseMachinePriceMapper leaseMachinePriceMapper;
@Override
@Transactional
public Result<String> addGoods(List<ShoppingCartInfoURDVo> shoppingCartInfoURDVoList) {
String userId = SecurityUtils.getUsername();
if (shoppingCartInfoURDVoList.isEmpty()) {
return Result.fail("请选择商品");
}
List<Long> machineIds = shoppingCartInfoURDVoList.stream().map(ShoppingCartInfoURDVo::getProductMachineId).collect(Collectors.toList());
List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectList(new LambdaQueryWrapper<LeaseProductMachine>()
.select(LeaseProductMachine::getId, LeaseProductMachine::getShopId)
.in(LeaseProductMachine::getId, machineIds));
Map<Long, Long> collect = leaseProductMachines.stream().collect(Collectors.toMap(LeaseProductMachine::getId, LeaseProductMachine::getShopId));
//获取用户购物车中所有矿机
List<LeaseShoppingCartInfo> leaseShoppingCartInfos = leaseShoppingCartInfoMapper
.selectList(new LambdaQueryWrapper<LeaseShoppingCartInfo>()
.eq(LeaseShoppingCartInfo::getUserId, userId));
// 存储需要新增的记录
List<LeaseShoppingCartInfo> newRecords = shoppingCartInfoURDVoList.stream()
.filter(vo -> leaseShoppingCartInfos.stream()
.noneMatch(info -> info.getProductMachineId().equals(vo.getProductMachineId())))
.map(shoppingCartInfoURDVo ->
LeaseShoppingCartInfo.builder()
.userId(userId)
.shopId(collect.get(shoppingCartInfoURDVo.getProductMachineId()))
.leaseTime(shoppingCartInfoURDVo.getLeaseTime())
.productId(shoppingCartInfoURDVo.getProductId())
.productMachineId(shoppingCartInfoURDVo.getProductMachineId())
.build()
).collect(Collectors.toList());
// 存储需要更新的记录
Map<Long, ShoppingCartInfoURDVo> voMap = shoppingCartInfoURDVoList.stream()
.collect(Collectors.toMap(ShoppingCartInfoURDVo::getProductMachineId, vo -> vo));
List<LeaseShoppingCartInfo> updateList = leaseShoppingCartInfos.stream()
.peek(info -> {
ShoppingCartInfoURDVo vo = voMap.get(info.getProductMachineId());
if (vo != null) {
info.setLeaseTime(info.getLeaseTime() + vo.getLeaseTime());
info.setId(info.getId());
}
})
.collect(Collectors.toList());
// 执行更新操作
if (!updateList.isEmpty()) {
boolean updateResult = leaseShoppingCartInfoService.updateBatchById(updateList);
if (!updateResult) {
return Result.fail("更新购物车租赁时间失败");
}
}
// 执行新增操作
if (!newRecords.isEmpty()) {
boolean saveResult = leaseShoppingCartInfoService.saveBatch(newRecords);
if (!saveResult) {
return Result.fail("添加新购物车记录失败");
}
}
return Result.success("添加购物车成功");
}
@Override
public PageResult<ShopCartDto> getGoodsList(PageVo pageVo) {
String userId = SecurityUtils.getUsername();
//检查购物车中是否存在商品
List<ShoppingCartInfoDto> cartInfoList = leaseShoppingCartInfoMapper.getProductAndMachineIds(userId,0);
if (cartInfoList.isEmpty()){
return PageResult.success(new ArrayList<>());
}
List<Long> machineIds = new ArrayList<>();
Map<Long, Integer> machineMap = new HashMap<>();
for (ShoppingCartInfoDto shoppingCartInfoDto : cartInfoList) {
machineIds.add(shoppingCartInfoDto.getProductMachineId());
machineMap.put(shoppingCartInfoDto.getProductMachineId(), shoppingCartInfoDto.getLeaseTime());
}
List<Long> shopIds = leaseShopMapper.getShopIdsByMachineIds(machineIds);
PageHelper.startPage(pageVo.getPageNum(), pageVo.getPageSize());
//查询购物车中店铺信息(一层)
List<LeaseShop> leaseShops = leaseShopMapper.selectList(new LambdaQueryWrapper<LeaseShop>().in(LeaseShop::getId, shopIds));
//获取商品售价
List<MachinePayTypeDto> machinePriceByMachineIds = leaseProductMachinePriceMapper.getMachinePriceByMachineIds(machineIds);
Map<Long, List<MachinePayTypeDto>> machinePriceMap = machinePriceByMachineIds.stream().collect(Collectors.groupingBy(MachinePayTypeDto::getProductMachineId));
//查询商品中机器详情 + 按照币种分组 (二层)
List<ProductMachineDto> leaseProductMachines = leaseProductMachineMapper.getMachinesByIds(machineIds);
//获取实时币价
List<String> coins = leaseProductMachines.stream().map(ProductMachineDto::getCoin).distinct().collect(Collectors.toList());
Map<String, BigDecimal> coinPriceMap = new HashMap<>();
Map<String, BigDecimal> coinRewardMap = new HashMap<>();
Map<String, BigDecimal> coinMhsMap = new HashMap<>();
for (String coin : coins) {
BigDecimal price = redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(coin));
BigDecimal reward =redisService.getCacheBigDecimal(RedisCoinInfoKey.getRewardKey(coin));
BigDecimal mhs = redisService.getCacheBigDecimal(RedisCoinInfoKey.getMhsKey(coin));
coinMhsMap.put(coin, mhs);
coinRewardMap.put(coin, reward);
coinPriceMap.put(coin, price);
}
//按币种查询每个矿机的最近一次30分钟的实时算力(后续修改为24小时平均算力)
List<ProductMachineDto> userMinerPowerList = new ArrayList<>();
Map<String, List<LeaseProductMachine>> userAndMinerList = leaseProductMachines.stream().map(
ProductMachineDto ->
LeaseProductMachine.builder()
.user(ProductMachineDto.getUser())
.miner(ProductMachineDto.getMiner())
.coin(ProductMachineDto.getCoin())
.build()
).collect(Collectors.groupingBy(LeaseProductMachine::getCoin));
userAndMinerList.forEach((coin, userMinerDtos) -> {
List<ProductMachineDto> recentlyFiveMinutesData = leaseProductMachineMapper.getRecentlyFiveMinutesData(userMinerDtos, coin);
List<ProductMachineDto> collect = recentlyFiveMinutesData.stream().peek(dto -> {
dto.setCoin(coin);
}).collect(Collectors.toList());
userMinerPowerList.addAll(collect);
});
Map<String, ProductMachineDto> realPowerList = userMinerPowerList.stream()
.collect(Collectors.toMap(
dto -> dto.getUser() + "-" + dto.getMiner() + "-" + dto.getCoin(),
dto -> dto
));
//为每个矿机设置实时的算力 + 按店铺分组
Map<Long, List<ProductMachineDto>> shopIdAndMachineInfoMap = leaseProductMachines.stream().peek(productMachineDto -> {
ProductMachineDto userMinerPowerDto = realPowerList.get(productMachineDto.getUser() + "-" + productMachineDto.getMiner() + "-" + productMachineDto.getCoin());
List<MachinePayTypeDto> machinePayTypeDtoList = machinePriceMap.get(productMachineDto.getId());
productMachineDto.setPriceList(machinePayTypeDtoList);
//理论收益
BigDecimal singleTheoryMachineIncome;
BigDecimal computingPower;
BigDecimal singleTheoryUSDTMachineIncome;
if (userMinerPowerDto != null) {
// 矿机算力单位转换 + 计算单矿机平均算力(ComputingPower coin_mhs30m 平均算力)
computingPower = PowerUnitUtils.getPower(productMachineDto.getUnit(),
userMinerPowerDto.getComputingPower()
.multiply(BigDecimal.valueOf(1000 * 1000))
.divide(BigDecimal.valueOf(24 * 60 * 60 ), 2, RoundingMode.HALF_UP));
BigDecimal mhs = coinMhsMap.get(productMachineDto.getCoin());
BigDecimal reward = coinRewardMap.get(productMachineDto.getCoin());
BigDecimal price = coinPriceMap.get(productMachineDto.getCoin());
if (mhs == null || reward == null || price == null){
singleTheoryMachineIncome = productMachineDto.getTheoryIncome();
singleTheoryUSDTMachineIncome = singleTheoryMachineIncome.multiply(price);
}else{
//全网算力单位转换
BigDecimal power = PowerUnitUtils.getPower(productMachineDto.getUnit(),mhs).multiply(BigDecimal.valueOf(1000 * 1000));
//(理论收益 = 矿机算力/全网算力 * 24h /出块间隔秒数 * 单块奖励redis中nexa:reward
singleTheoryMachineIncome = computingPower.divide( power,6, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(24 * 60 * 60)
.divide(BlockInterval.getBlockCountByCoinName(productMachineDto.getCoin()), 6, RoundingMode.HALF_UP)).multiply(reward);
singleTheoryUSDTMachineIncome = singleTheoryMachineIncome.multiply(price);
}
//单位为MH/s 需要转换成 矿机设定的单位
productMachineDto.setComputingPower(computingPower);
productMachineDto.setTheoryIncome(singleTheoryMachineIncome);
productMachineDto.setTheoryUsdtIncome(singleTheoryUSDTMachineIncome);
}
}).collect(Collectors.groupingBy(ProductMachineDto::getShopId));
//获取商铺钱包配置信息
List<PayConfigDto> shopWalletInfo = leaseShopMapper.getShopWalletInfoList(shopIds);
Map<Long, List<PayConfigDto>> payConfigMap = shopWalletInfo.stream()
.map(payConfigDto->{
payConfigDto.setDeductibleAmount(CoinCharge.getDeductibleAmountByChainAndCoin(payConfigDto.getPayChain(), payConfigDto.getPayCoin()));
payConfigDto.setFee(CoinCharge.getChargeByChainAndCoin(payConfigDto.getPayChain(), payConfigDto.getPayCoin()));
return payConfigDto;
})
.collect(Collectors.groupingBy(PayConfigDto::getShopId));
//组合返回对象
List<ShopCartDto> shopCartList = leaseShops.stream().map(leaseShop -> {
List<ProductMachineDto> productMachineList = shopIdAndMachineInfoMap.get(leaseShop.getId());
return ShopCartDto.builder()
.id(leaseShop.getId())
.name(leaseShop.getName())
.totalMachine(productMachineList != null ? productMachineList.size() : 0)
.payConfigList(payConfigMap.get(leaseShop.getId()))
.productMachineDtoList(productMachineList)
.build();
}).collect(Collectors.toList());
//计算不同链和币种对应的总售价
for (ShopCartDto shopCartDto : shopCartList) {
//遍历每个商铺下的矿机
List<ProductMachineDto> productMachineDtoList = shopCartDto.getProductMachineDtoList();
Map<String, BigDecimal> totalPriceMap = new HashMap<>();
Map<String, MachineTotalPriceDto> totalPriceDtoMap = new HashMap<>();
for (ProductMachineDto productMachineDto : productMachineDtoList) {
Integer leaseTime = machineMap.get(productMachineDto.getId());
productMachineDto.setLeaseTime(leaseTime);
List<MachinePayTypeDto> priceList = productMachineDto.getPriceList();
for (MachinePayTypeDto machinePayTypeDto : priceList) {
BigDecimal itemPrice = machinePayTypeDto.getPrice().multiply(new BigDecimal(leaseTime));
String key = machinePayTypeDto.getCoin()+"-"+machinePayTypeDto.getChain();
totalPriceMap.merge(key, itemPrice, BigDecimal::add);
totalPriceDtoMap.put(key,new MachineTotalPriceDto(BigDecimal.ZERO, machinePayTypeDto.getChain(), machinePayTypeDto.getCoin()));
}
}
totalPriceDtoMap.forEach((key, value) -> {
value.setPrice(totalPriceMap.get(key));
});
shopCartDto.setTotalPriceList(new ArrayList<>(totalPriceDtoMap.values()));
}
PageInfo<ShopCartDto> pageInfo = new PageInfo<>(shopCartList);
PageResult<ShopCartDto> success = PageResult.success(shopCartList);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
@Override
@Transactional
public Result<String> deleteBatchGoods(List<ProductAndMachineVo> baseVoList) {
List<LeaseShoppingCartInfo> leaseShoppingCartInfos = leaseShoppingCartInfoMapper.selectList(new LambdaQueryWrapper<LeaseShoppingCartInfo>()
.eq(LeaseShoppingCartInfo::getUserId, SecurityUtils.getUsername())
.eq(LeaseShoppingCartInfo::getVersion, 0));
if (leaseShoppingCartInfos.isEmpty()){
return Result.fail("删除购物车商品失败,购物车中不存在商品");
}
List<Long> ids = new ArrayList<>();
for (LeaseShoppingCartInfo leaseShoppingCartInfo : leaseShoppingCartInfos) {
for (ProductAndMachineVo baseVo : baseVoList){
if (leaseShoppingCartInfo.getProductMachineId().equals(baseVo.getMachineId())){
ids.add(leaseShoppingCartInfo.getId());
}
}
}
if (ids.isEmpty()){
return Result.fail("删除购物车商品失败,购物车中不存在该商品");
}
leaseShoppingCartInfoMapper.deleteBatchData(ids);
return Result.success("删除购物车商品成功");
}
@Override
@Transactional
public Result<String> deleteGoods(BaseVo baseVo) {
int delete = leaseShoppingCartInfoMapper.deleteById(baseVo.getId());
if (delete > 0){
return Result.success("删除购物车商品成功");
}
return Result.fail("删除购物车商品失败");
}
@Override
public Result<String> deleteBatchGoodsForIsDelete() {
List<LeaseShoppingCartInfo> leaseShoppingCartInfos = leaseShoppingCartInfoMapper.selectList(new LambdaQueryWrapper<LeaseShoppingCartInfo>()
.eq(LeaseShoppingCartInfo::getUserId, SecurityUtils.getUsername()));
List<Long> machineIds = leaseShoppingCartInfos.stream().map(LeaseShoppingCartInfo::getProductMachineId)
.collect(Collectors.toList());
List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectList(new LambdaQueryWrapper<LeaseProductMachine>()
.in(LeaseProductMachine::getId, machineIds));
List<Long> delMachineIds = leaseProductMachines.stream().filter(productMachine -> productMachine.getDel() || productMachine.getState() == 1)
.map(LeaseProductMachine::getId).collect(Collectors.toList());
if (delMachineIds.isEmpty()){
return Result.success("删除购物车已下架商品成功");
}
int delete = leaseShoppingCartInfoMapper.delete(new LambdaUpdateWrapper<LeaseShoppingCartInfo>()
.in(LeaseShoppingCartInfo::getProductMachineId, delMachineIds));
if (delete > 0){
return Result.success("删除购物车已下架商品成功");
}
return Result.fail("删除失败,不存在已下架商品");
}
@Override
public Result<String> addGoodsV2(List<AddGoodsVo> addGoodsVoList) {
String userId = SecurityUtils.getUsername();
if (addGoodsVoList.isEmpty()) {
return Result.fail("请选择商品");
}
List<Long> machineIds = addGoodsVoList.stream().map(AddGoodsVo::getId).collect(Collectors.toList());
List<LeaseMachine> leaseProductMachines = leaseMachineMapper.selectList(new LambdaQueryWrapper<LeaseMachine>()
.select(LeaseMachine::getId, LeaseMachine::getShopId)
.in(LeaseMachine::getId, machineIds));
Map<Long, Long> collect = leaseProductMachines.stream()
.collect(Collectors.toMap(LeaseMachine::getId, LeaseMachine::getShopId));
//获取用户购物车中所有矿机
List<LeaseShoppingCartInfo> leaseShoppingCartInfos = leaseShoppingCartInfoMapper
.selectList(new LambdaQueryWrapper<LeaseShoppingCartInfo>()
.eq(LeaseShoppingCartInfo::getUserId, userId));
// 存储需要新增的记录
List<LeaseShoppingCartInfo> newRecords = addGoodsVoList.stream()
.filter(vo -> leaseShoppingCartInfos.stream()
.noneMatch(info -> info.getProductMachineId().equals(vo.getId())))
.map(shoppingCartInfoURDVo ->
LeaseShoppingCartInfo.builder()
.userId(userId)
.shopId(collect.get(shoppingCartInfoURDVo.getId()))
.leaseTime(shoppingCartInfoURDVo.getLeaseTime())
.numbers(shoppingCartInfoURDVo.getNumbers())
.productMachineId(shoppingCartInfoURDVo.getId())
.version(1)
.build()
).collect(Collectors.toList());
// 存储需要更新的记录
Map<Long, AddGoodsVo> voMap = addGoodsVoList.stream()
.collect(Collectors.toMap(AddGoodsVo::getId, vo -> vo));
List<LeaseShoppingCartInfo> updateList = leaseShoppingCartInfos.stream()
.peek(info -> {
AddGoodsVo vo = voMap.get(info.getProductMachineId());
if (vo != null && vo.getNumbers() != null) {
info.setNumbers(info.getNumbers()+vo.getNumbers());
info.setLeaseTime(info.getLeaseTime() + vo.getLeaseTime());
info.setId(info.getId());
}
})
.collect(Collectors.toList());
// 执行更新操作
if (!updateList.isEmpty()) {
boolean updateResult = leaseShoppingCartInfoService.updateBatchById(updateList);
if (!updateResult) {
return Result.fail("更新购物车租赁时间失败");
}
}
// 执行新增操作
if (!newRecords.isEmpty()) {
boolean saveResult = leaseShoppingCartInfoService.saveBatch(newRecords);
if (!saveResult) {
return Result.fail("添加新购物车记录失败");
}
}
return Result.success("添加购物车成功");
}
@Override
public PageResult<ShopCartV2Dto> getGoodsListV2(PageVo pageVo) {
String userId = SecurityUtils.getUsername();
//检查购物车中是否存在商品
List<ShoppingCartInfoDto> cartInfoList = leaseShoppingCartInfoMapper.getProductAndMachineIds(userId,1);
if (cartInfoList.isEmpty()){
return PageResult.success(new ArrayList<>());
}
List<Long> machineIds = new ArrayList<>();
Map<Long, Integer> machineMap = new HashMap<>();
for (ShoppingCartInfoDto shoppingCartInfoDto : cartInfoList) {
machineIds.add(shoppingCartInfoDto.getProductMachineId());
machineMap.put(shoppingCartInfoDto.getProductMachineId(), shoppingCartInfoDto.getLeaseTime());
}
List<Long> shopIds = leaseMachineMapper.getShopIdsByMachineIds(machineIds);
PageHelper.startPage(pageVo.getPageNum(), pageVo.getPageSize());
//查询购物车中店铺信息(一层)
List<LeaseShop> leaseShops = leaseShopMapper.selectList(new LambdaQueryWrapper<LeaseShop>()
.in(LeaseShop::getId, shopIds));
//获取商品售价
List<MachinePayTypeDto> machinePriceByMachineIds = leaseMachinePriceMapper.getMachinePriceByMachineIds(machineIds);
Map<Long, List<MachinePayTypeDto>> machinePriceMap = machinePriceByMachineIds.stream()
.collect(Collectors.groupingBy(MachinePayTypeDto::getProductMachineId));
//查询店铺中机器详情
List<CartMachineInfoDto> leaseProductMachines = leaseMachineMapper.getMachinesByIds(machineIds);
//设置每个矿机的售价,并按店铺分组
Map<Long, List<CartMachineInfoDto>> shopIdAndMachineInfoMap = leaseProductMachines.stream()
.peek(productMachineDto -> {
productMachineDto.setPriceList(machinePriceMap.get(productMachineDto.getId()));
})
.collect(Collectors.groupingBy(CartMachineInfoDto::getShopId));
//获取商铺钱包配置信息
List<PayConfigDto> shopWalletInfo = leaseShopMapper.getShopWalletInfoList(shopIds);
Map<Long, List<PayConfigDto>> payConfigMap = shopWalletInfo.stream()
.map(payConfigDto->{
payConfigDto.setDeductibleAmount(CoinCharge.getDeductibleAmountByChainAndCoin(payConfigDto.getPayChain(), payConfigDto.getPayCoin()));
payConfigDto.setFee(CoinCharge.getChargeByChainAndCoin(payConfigDto.getPayChain(), payConfigDto.getPayCoin()));
return payConfigDto;
})
.collect(Collectors.groupingBy(PayConfigDto::getShopId));
//组合返回对象
List<ShopCartV2Dto> shopCartList = leaseShops.stream().map(leaseShop -> {
List<CartMachineInfoDto> productMachineList = shopIdAndMachineInfoMap.get(leaseShop.getId());
return ShopCartV2Dto.builder()
.id(leaseShop.getId())
.name(leaseShop.getName())
.totalMachine(productMachineList != null ? productMachineList.size() : 0)
.payConfigList(payConfigMap.get(leaseShop.getId()))
.cartMachineInfoDtoList(productMachineList)
.build();
}).collect(Collectors.toList());
//计算不同链和币种对应的总售价
for (ShopCartV2Dto shopCartDto : shopCartList) {
//遍历每个商铺下的矿机
List<CartMachineInfoDto> productMachineDtoList = shopCartDto.getCartMachineInfoDtoList();
Map<String, BigDecimal> totalPriceMap = new HashMap<>();
Map<String, MachineTotalPriceDto> totalPriceDtoMap = new HashMap<>();
for (CartMachineInfoDto productMachineDto : productMachineDtoList) {
Integer leaseTime = machineMap.get(productMachineDto.getId());
productMachineDto.setLeaseTime(leaseTime);
List<MachinePayTypeDto> priceList = productMachineDto.getPriceList();
for (MachinePayTypeDto machinePayTypeDto : priceList) {
BigDecimal itemPrice = machinePayTypeDto.getPrice().multiply(new BigDecimal(leaseTime))
.multiply(BigDecimal.valueOf(productMachineDto.getNumbers()));
String key = machinePayTypeDto.getCoin()+"-"+machinePayTypeDto.getChain();
totalPriceMap.merge(key, itemPrice, BigDecimal::add);
totalPriceDtoMap.put(key,new MachineTotalPriceDto(BigDecimal.ZERO, machinePayTypeDto.getChain(), machinePayTypeDto.getCoin()));
}
}
totalPriceDtoMap.forEach((key, value) -> {
value.setPrice(totalPriceMap.get(key));
});
shopCartDto.setTotalPriceList(new ArrayList<>(totalPriceDtoMap.values()));
}
PageInfo<ShopCartV2Dto> pageInfo = new PageInfo<>(shopCartList);
PageResult<ShopCartV2Dto> success = PageResult.success(shopCartList);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
@Override
public Result<String> deleteBatchGoodsV2(List<CartInfoVo> baseVoList) {
List<Long> ids = baseVoList.stream().map(CartInfoVo::getCartInfoId).collect(Collectors.toList());
leaseShoppingCartInfoMapper.deleteBatchData(ids);
return Result.success("删除购物车商品成功");
}
@Override
public Result<String> deleteBatchGoodsForIsDeleteV2() {
List<LeaseShoppingCartInfo> leaseShoppingCartInfos = leaseShoppingCartInfoMapper.selectList(new LambdaQueryWrapper<LeaseShoppingCartInfo>()
.eq(LeaseShoppingCartInfo::getUserId, SecurityUtils.getUsername()));
List<Long> machineIds = leaseShoppingCartInfos.stream().map(LeaseShoppingCartInfo::getProductMachineId).collect(Collectors.toList());
List<LeaseMachine> leaseMachines = leaseMachineMapper.selectList(new LambdaQueryWrapper<LeaseMachine>()
.in(LeaseMachine::getId, machineIds));
List<Long> delMachineIds = leaseMachines.stream().filter(machine -> machine.getDel() || machine.getState())
.map(LeaseMachine::getId).collect(Collectors.toList());
if (delMachineIds.isEmpty()){
return Result.success("删除购物车已下架商品成功");
}
int delete = leaseShoppingCartInfoMapper.delete(new LambdaUpdateWrapper<LeaseShoppingCartInfo>()
.in(LeaseShoppingCartInfo::getProductMachineId, delMachineIds));
if (delete > 0){
return Result.success("删除购物车已下架商品成功");
}
return Result.fail("删除失败,不存在已下架商品");
}
}

View File

@@ -0,0 +1,21 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.entity.LeaseShoppingCartInfo;
import com.m2pool.lease.mapper.LeaseShoppingCartInfoMapper;
import com.m2pool.lease.service.LeaseShoppingCartInfoService;
import org.springframework.stereotype.Service;
/**
* <p>
* 购物车详情表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-24
*/
@Service
public class LeaseShoppingCatInfoServiceImpl extends ServiceImpl<LeaseShoppingCartInfoMapper, LeaseShoppingCartInfo> implements LeaseShoppingCartInfoService {
}

View File

@@ -0,0 +1,208 @@
package com.m2pool.lease.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.m2pool.lease.redis.RedisCoinInfoKey;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.*;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.redis.service.RedisService;
import com.m2pool.lease.service.LeaseUserOwnedProductService;
import com.m2pool.lease.utils.SecurityUtils;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.UserOwnedProductVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <p>
* 用户拥有商品详情表 服务实现类
* </p>
*
* @author yyb
* @since 2025-07-23
*/
@Service
public class LeaseUserOwnedProductServiceImpl extends ServiceImpl<LeaseUserOwnedProductMapper, LeaseUserOwnedProduct> implements LeaseUserOwnedProductService {
@Resource
private LeaseUserOwnedProductMapper leaseUserOwnedProductMapper;
@Resource
private LeaseProductMachineMapper leaseProductMachineMapper;
@Resource
private RedisService redisService;
@Override
public PageResult<UserOwnedProductDto> getOwnedList(UserOwnedProductVo userOwnedProductVo) {
PageHelper.startPage(userOwnedProductVo.getPageNum(), userOwnedProductVo.getPageSize());
//查询已购买的商品集合 按租约状态 未过期在前 + 结束时间 最先结束的在前排序
List<LeaseUserOwnedProduct> leaseUserOwnedProducts = leaseUserOwnedProductMapper.selectList(new LambdaQueryWrapper<LeaseUserOwnedProduct>()
.eq(LeaseUserOwnedProduct::getUserId, SecurityUtils.getUsername())
.eq(LeaseUserOwnedProduct::getDel, false)
.orderByAsc(LeaseUserOwnedProduct::getStatus)
.orderByDesc(LeaseUserOwnedProduct::getEndTime));
PageInfo<LeaseUserOwnedProduct> pageInfo = new PageInfo<>(leaseUserOwnedProducts);
if (leaseUserOwnedProducts.isEmpty()){
//不存在已购商品
PageResult<UserOwnedProductDto> fail = PageResult.success(null);
PageHelper.clearPage();
return fail;
}
Map<String, List<UserMinerDto>> userAndMinerList = leaseUserOwnedProducts.stream().map(
leaseUserOwnedProduct ->
UserMinerDto.builder()
.user(leaseUserOwnedProduct.getUser())
.miner(leaseUserOwnedProduct.getMiner())
.coin(leaseUserOwnedProduct.getCoin())
.build()
).collect(Collectors.groupingBy(UserMinerDto::getCoin));
List<UserMinerPowerDto> userMinerPowerList = new ArrayList<>();
userAndMinerList.forEach((coin, userMinerDtos) -> {
userMinerPowerList.addAll( leaseUserOwnedProductMapper.getUserMinerPower(userMinerDtos, coin));
});
//根据user+miner+coin 获取到实时的算力
Map<String, UserMinerPowerDto> collect = userMinerPowerList.stream()
.collect(Collectors.toMap(
dto -> dto.getUser() + "-" + dto.getMiner() + "-" + dto.getCoin(),
dto -> dto
));
//获取币价
Map<String, BigDecimal> coinPrice = new HashMap<>();
//封装返回对象
List<UserOwnedProductDto> userOwnedProducts = leaseUserOwnedProducts.stream().map(leaseUserOwnedProduct ->{
String coin = leaseUserOwnedProduct.getCoin();
BigDecimal bigDecimal = coinPrice.putIfAbsent(coin, redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(coin)));
UserOwnedProductDto build = UserOwnedProductDto.builder()
.id(leaseUserOwnedProduct.getId())
.userId(leaseUserOwnedProduct.getUserId())
.productMachineId(leaseUserOwnedProduct.getProductMachineId())
.orderItemId(leaseUserOwnedProduct.getOrderItemId())
.startTime(leaseUserOwnedProduct.getStartTime())
.productMachineId(leaseUserOwnedProduct.getProductMachineId())
.endTime(leaseUserOwnedProduct.getEndTime())
.currentIncome(leaseUserOwnedProduct.getCurrentIncome())
.estimatedEndIncome(leaseUserOwnedProduct.getEstimatedEndIncome())
.currentUsdtIncome(bigDecimal == null ? leaseUserOwnedProduct.getCurrentUsdtIncome() : bigDecimal.multiply(leaseUserOwnedProduct.getCurrentIncome()))
.estimatedEndUsdtIncome(leaseUserOwnedProduct.getEstimatedEndUsdtIncome())
.purchasedComputingPower(leaseUserOwnedProduct.getPurchasedComputingPower())
.status(leaseUserOwnedProduct.getStatus())
.type(leaseUserOwnedProduct.getType())
.createTime(leaseUserOwnedProduct.getCreateTime())
.build();
UserMinerPowerDto userMinerPowerDto = collect.get(leaseUserOwnedProduct.getUser() + "-" + leaseUserOwnedProduct.getMiner() + "-"+ leaseUserOwnedProduct.getCoin());
if (userMinerPowerDto != null){
//已购机器30分算力
build.setCurrentComputingPower(userMinerPowerDto.getPower());
}
return build;
}).collect(Collectors.toList());
PageResult<UserOwnedProductDto> success = PageResult.success(userOwnedProducts);
success.setTotal(pageInfo.getTotal());
success.setTotalPage(pageInfo.getPages());
PageHelper.clearPage();
return success;
}
@Override
public Result<UserOwnedProductDto> getOwnedById(BaseVo baseVo) {
LeaseUserOwnedProduct leaseUserOwnedProduct = leaseUserOwnedProductMapper.selectById(baseVo.getId());
List<LeaseProductMachine> leaseProductMachines = new ArrayList<>();
leaseProductMachines.add(LeaseProductMachine.builder()
.user(leaseUserOwnedProduct.getUser())
.miner(leaseUserOwnedProduct.getMiner())
.build());
BigDecimal price = redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(leaseUserOwnedProduct.getCoin()));
//获取实时算力
List<ProductMachineDto> recentlyFiveMinutesData = leaseProductMachineMapper.getRecentlyFiveMinutesData(leaseProductMachines, leaseUserOwnedProduct.getCoin());
Integer status = leaseUserOwnedProduct.getStatus();
BigDecimal currentIncome = status == 0 ? leaseUserOwnedProduct.getSettleIncome() : leaseUserOwnedProduct.getCurrentIncome();
BigDecimal currentUsdtIncome = currentIncome.multiply(price);
UserOwnedProductDto build = UserOwnedProductDto.builder()
.id(leaseUserOwnedProduct.getId())
.userId(leaseUserOwnedProduct.getUserId())
.productMachineId(leaseUserOwnedProduct.getProductMachineId())
.orderItemId(leaseUserOwnedProduct.getOrderItemId())
.startTime(leaseUserOwnedProduct.getStartTime())
.productMachineId(leaseUserOwnedProduct.getProductMachineId())
.endTime(leaseUserOwnedProduct.getEndTime())
.estimatedEndIncome(leaseUserOwnedProduct.getEstimatedEndIncome())
.estimatedEndUsdtIncome(leaseUserOwnedProduct.getEstimatedEndUsdtIncome())
.purchasedComputingPower(leaseUserOwnedProduct.getPurchasedComputingPower())
.currentIncome(currentIncome)
.currentUsdtIncome(currentUsdtIncome)
.status(status)
.type(leaseUserOwnedProduct.getType())
.createTime(leaseUserOwnedProduct.getCreateTime())
.build();
if (!recentlyFiveMinutesData.isEmpty()){
build.setCurrentComputingPower(recentlyFiveMinutesData.get(0).getComputingPower().divide(BigDecimal.valueOf(24 * 60 * 60), 2, RoundingMode.HALF_UP));
}
return Result.success(build);
}
/**
* 支付验证成功后去修改订单等信息(迁移到这里让事务生效)
* @param leaseOrderItems
* @return 支付订单验证成功的个数
*/
@Transactional
@Override
public boolean afterPaySuccessTodoSomeEvent(List<LeaseOrderItem> leaseOrderItems){
//回调才需要
// 修改商品售出状态
//List<Long> ids = leaseOrderItems.stream().map(LeaseOrderItem::getProductMachineId).collect(Collectors.toList());
//int update = leaseProductMachineMapper.update(LeaseProductMachine.builder().saleState(1).build(),
// new LambdaQueryWrapper<LeaseProductMachine>().eq(LeaseProductMachine::getDel, false).in(LeaseProductMachine::getId, ids));
// 添加购买记录
//List<LeaseOrderItem> leaseOrderItems2 = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
// .in(LeaseOrderItem::getProductMachineId, ids));
//获取卖方收款币种币价
BigDecimal price = redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(leaseOrderItems.get(0).getCoin()));
List<LeaseUserOwnedProduct> collect = leaseOrderItems.stream()
.map(item -> {
// 获取当前的 LocalDateTime
LocalDateTime now = LocalDateTime.now();
// 获取当天 0 点的 LocalDateTime
LocalDateTime startOfDay = now.toLocalDate().atStartOfDay().plusDays(1);
return LeaseUserOwnedProduct.builder()
.miner(item.getMiner())
.userId(SecurityUtils.getUsername())
.user(item.getUser())
.address(item.getAddress())
.productMachineId(item.getProductMachineId())
.orderItemId(item.getId())
.orderId(item.getOrderId())
//预估收益由订单创建时固定 实际收益通过定时任务实时计算
.estimatedEndIncome(item.getTheoryIncome())
.estimatedEndUsdtIncome(price == null ? BigDecimal.ZERO : item.getTheoryIncome().multiply(price))
.coin(item.getCoin())
.startTime(startOfDay)
.type(item.getType() ? 1 : 0)
.endTime(startOfDay.plusDays(item.getLeaseTime()))
.build();
}).collect(Collectors.toList());
boolean b1 = saveBatch(collect);
return b1;
}
}

File diff suppressed because it is too large Load Diff