Helius
2022-03-09 38179780b2f728abe6dd0e5aaa284c6ee6aa8380
init otc
30 files modified
72 files added
4733 ■■■■■ changed files
src/main/java/com/xcong/excoin/common/contants/AppContants.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/RabbitMqConfig.java 42 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/configurations/properties/ApplicationProperties.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/controller/MemberController.java 16 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/dao/MemberPaymentMethodDao.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/dao/MemberSettingDao.java 1 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletCoinDao.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/entity/MemberSettingEntity.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/service/MemberService.java 4 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/service/impl/MemberServiceImpl.java 38 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/member/vo/DefaultWayVo.java 18 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/controller/OtcBlackListController.java 101 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/controller/OtcEntrustOrderController.java 122 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/controller/OtcMarketBussinessController.java 117 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/controller/OtcMsgController.java 93 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/controller/OtcOrderController.java 124 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dao/OtcBlackListDao.java 19 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dao/OtcEntrustOrderDao.java 24 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dao/OtcMarketBussinessDao.java 10 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dao/OtcMsgHistoryDao.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dao/OtcMsgUserListDao.java 19 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dao/OtcOrderAppealDao.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dao/OtcOrderDao.java 46 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dao/OtcReturnMoneyDao.java 17 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dao/OtcSettingDao.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/AddBlackDto.java 25 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/BlackListDto.java 16 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/ChatBoxDto.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/ChatOrderDto.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/ConnectDto.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/EntrustOrderAddDto.java 38 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/EntrustOrderListDto.java 30 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/HasPayDto.java 16 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/MbAddDto.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/MsgListDto.java 20 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/OrderApealDto.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/OrderListDto.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/OtcOrderAddDto.java 29 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/SendMsgDto.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/dto/TeamDto.java 15 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/entity/OtcBlackList.java 17 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/entity/OtcEntrustOrder.java 79 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/entity/OtcMarketBussiness.java 60 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/entity/OtcMsgHistoryEntity.java 30 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/entity/OtcMsgUserListEntity.java 34 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/entity/OtcOrder.java 96 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/entity/OtcOrderAppeal.java 31 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/entity/OtcReturnMoney.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/entity/OtcSetting.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/mapper/OtcEntrustOrderMapper.java 39 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/mapper/OtcMarketBussinessMapper.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/OtcEntrustOrderService.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/OtcMarketBussinessService.java 17 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/OtcMsgService.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/OtcOrderAppealService.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/OtcOrderService.java 32 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcEntrustOrderServiceImpl.java 230 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcMarketBussinessServiceImpl.java 180 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcMsgServiceImpl.java 252 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcOrderAppealServiceImpl.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcOrderServiceImpl.java 507 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/ApplyConditionsVo.java 37 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/BlackListVo.java 24 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/BuyOrderDetailVo.java 82 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/ChatBoxVo.java 38 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/ChatOrderVo.java 62 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/EntrustListInfoVo.java 66 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/EntrustListVo.java 63 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/EntrustOrderDetailVo.java 82 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/MarketBussinessInfoVo.java 51 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/MsgListVo.java 39 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/OrderListVo.java 43 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/SaleOrderDetailVo.java 73 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/otc/vo/TeamVo.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/bean/AuthRequest.java 29 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/bean/ChatRequest.java 31 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/bean/RequestBean.java 73 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/bean/ResponseBean.java 83 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/common/ChannelManager.java 37 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/common/Contans.java 12 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/common/NettyTools.java 11 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/dispatch/MsgDispatch.java 31 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/handler/WebSocketServerHandler.java 37 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/initalizer/WebSocketServerInitializer.java 7 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/logic/WebSocketLogic.java 83 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/logic/impl/MsgLogicImpl.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/netty/server/WebSocketServer.java 13 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/quartz/job/NettyServerStartUp.java 21 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/quartz/job/OtcOrderJob.java 131 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/rabbit/consumer/ChatConsumer.java 106 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/rabbit/consumer/OtcConsumer.java 161 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/rabbit/producer/ChatProducer.java 33 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/rabbit/producer/OtcProducter.java 68 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/utils/ThreadPoolUtils.java 9 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/utils/dingtalk/DingTalkUtils.java 87 ●●●● patch | view | raw | blame | history
src/main/resources/application-prod.yml 3 ●●●●● patch | view | raw | blame | history
src/main/resources/application-prodapp.yml 3 ●●●●● patch | view | raw | blame | history
src/main/resources/application.yml 3 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/member/MemberPaymentMethodDao.xml 15 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/member/MemberSettingDao.xml 6 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/member/MemberWalletCoinDao.xml 6 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/common/contants/AppContants.java
@@ -83,4 +83,11 @@
    public static final BigDecimal DEFAULT_PRICE = BigDecimal.valueOf(1.28);
    public static final String OTC_ORDER_CANCEL_TIMES = "OTC_ORDER_CANCEL_TIMES_";
    public static final String MSG_NOTICE = "MSG_NOTICE_";
    public static final String MSG_CHATTING = "MSG_CHATTING_";
}
src/main/java/com/xcong/excoin/configurations/RabbitMqConfig.java
@@ -130,6 +130,15 @@
    public static final String QUEUE_TRC20_BLOCK = "QUEUE_TRC20_BLOCK";
    public static final String ROUTING_TRC20_BLOCK = "ROUTING_TRC20_BLOCK";
    public static final String QUEUE_MSG_HISTORY = "queue_msg_history";
    public static final String ROUTING_KEY_MSG_HISTORY = "routing_key_msg_history";
    public static final String ROUTINGKEY_MARKET_BUSSINESS = "ROUTINGKEY_MARKET_BUSSINESS";
    public static final String QUEUE_MARKET_BUSSINESS = "QUEUE_MARKET_BUSSINESS";
    public static final String QUEUE_ORDER_RETURN = "QUEUE_ORDER_RETURN";
    public static final String ROUTING_ORDER_RETURN = "ROUTING_ORDER_RETURN";
    @Resource
    private ConnectionFactory connectionFactory;
@@ -142,6 +151,39 @@
//        return connectionFactory;
//    }
    // ========= otc start =============
    @Bean
    public Queue orderReturnQueue() {
        return new Queue(QUEUE_ORDER_RETURN);
    }
    @Bean
    public Binding orderReturnBinding() {
        return BindingBuilder.bind(orderReturnQueue()).to(defaultExchange()).with(ROUTING_ORDER_RETURN);
    }
    @Bean
    public Queue marketBussinessQueue() {
        return new Queue(QUEUE_MARKET_BUSSINESS);
    }
    @Bean
    public Binding marketBussinessBinding() {
        return BindingBuilder.bind(marketBussinessQueue()).to(defaultExchange()).with(ROUTINGKEY_MARKET_BUSSINESS);
    }
    @Bean
    public Queue msgHistoryQueue() {
        return new Queue(QUEUE_MSG_HISTORY);
    }
    @Bean
    public Binding msgHistoryBinding() {
        return BindingBuilder.bind(msgHistoryQueue()).to(defaultExchange()).with(ROUTING_KEY_MSG_HISTORY);
    }
    // ========= otc end =============
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public RabbitTemplate rabbitTemplate() {
src/main/java/com/xcong/excoin/configurations/properties/ApplicationProperties.java
@@ -17,4 +17,6 @@
    private boolean debug;
    private Long redisExpire;
    private String project;
}
src/main/java/com/xcong/excoin/modules/member/controller/MemberController.java
@@ -6,6 +6,7 @@
import com.xcong.excoin.modules.coin.parameter.dto.RecordsPageDto;
import com.xcong.excoin.modules.member.parameter.dto.*;
import com.xcong.excoin.modules.member.parameter.vo.*;
import com.xcong.excoin.modules.member.vo.DefaultWayVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -210,6 +211,21 @@
    public Result memberPaymethodDetailList() {
        return memberService.memberPaymethodDetailList();
    }
    @ApiOperation(value = "设置为默认收款方式")
    @PostMapping(value = "/setDefaultMethod/{id}")
    public Result setDefaultMethod(@PathVariable("id") Long id) {
        return memberService.setDefaultPaymethod(id);
    }
    @ApiOperation(value = "获取我的默认收款方式", notes = "获取我的默认收款方式")
    @ApiResponses({
            @ApiResponse(code = 200, message = "获取成功", response = DefaultWayVo.class)
    })
    @GetMapping(value = "/findDefaultWay")
    public Result findDefaultWay() {
        return memberService.findDefaultWay();
    }
    
    /**
     * 绑定手机号
src/main/java/com/xcong/excoin/modules/member/dao/MemberPaymentMethodDao.java
@@ -4,8 +4,11 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xcong.excoin.modules.member.entity.MemberPaymentMethodEntity;
import org.apache.ibatis.annotations.Param;
public interface MemberPaymentMethodDao extends BaseMapper<MemberPaymentMethodEntity> {
    public List<MemberPaymentMethodEntity> selectByMemberId(Long memberId);
    MemberPaymentMethodEntity selectDefualtMethod(@Param("memberId") Long memberId, @Param("type") Integer type, @Param("isDefault") String isDefault);
}
src/main/java/com/xcong/excoin/modules/member/dao/MemberSettingDao.java
@@ -16,4 +16,5 @@
    public int batchInsert(@Param("list") List<MemberSettingEntity> list);
    public void updateMessageReminderByMemberId(@Param("memberId")Long memberId);
}
src/main/java/com/xcong/excoin/modules/member/dao/MemberWalletCoinDao.java
@@ -23,4 +23,6 @@
    int updateBlockBalance(@Param("id") Long id, @Param("availableBalance") BigDecimal availableBalance, @Param("earlyBalance") BigDecimal earlyBalance, @Param("blockNumber") Integer blockNumber);
    int updateWalletBalance(@Param("id") Long id, @Param("availableBalance") BigDecimal availableBalance, @Param("totalBalance") BigDecimal totalBalance, @Param("frozenBalance") BigDecimal frozenBalance);
    int reduceFrozenBalance(@Param("id") Long id, @Param("amount") BigDecimal amount);
}
src/main/java/com/xcong/excoin/modules/member/entity/MemberEntity.java
@@ -75,11 +75,17 @@
    public static final int IS_PROFIT_N = 0;
    public static final Integer IS_TRADER_Y = 1;
    public static final Integer IS_TRADER_N = 2;
    /**
     * 手机号(包含国际手机号)
     */
    private String phone;
    private String name;
    /**
     * 邮箱
     */
src/main/java/com/xcong/excoin/modules/member/entity/MemberSettingEntity.java
@@ -31,4 +31,6 @@
     */
    private BigDecimal forceParam;
    private int messageReminder;
}
src/main/java/com/xcong/excoin/modules/member/service/MemberService.java
@@ -41,6 +41,8 @@
    public Result memberPaymethodDetailList();
    Result setDefaultPaymethod(Long id);
    public Result memberBindPhone(@Valid MemberBindPhoneDto memberBindPhoneDto);
    public Result memberBindEmail(@Valid MemberBindEmailDto memberBindEmailDto);
@@ -80,4 +82,6 @@
    public Result getPcVersionInfo();
    Result memberTeam(MemberTeamRecordsPageDto memberTeamRecordsPageDto);
    Result findDefaultWay();
}
src/main/java/com/xcong/excoin/modules/member/service/impl/MemberServiceImpl.java
@@ -28,6 +28,7 @@
import com.xcong.excoin.modules.member.parameter.dto.*;
import com.xcong.excoin.modules.member.parameter.vo.*;
import com.xcong.excoin.modules.member.service.MemberService;
import com.xcong.excoin.modules.member.vo.DefaultWayVo;
import com.xcong.excoin.modules.platform.dao.PlatformFeeSettingDao;
import com.xcong.excoin.modules.platform.dao.PlatformSymbolsCoinDao;
import com.xcong.excoin.modules.platform.entity.PlatformFeeSettingEntity;
@@ -601,6 +602,29 @@
    }
    @Override
    public Result setDefaultPaymethod(Long id) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        MemberPaymentMethodEntity defualtMethod = this.memberPaymentMethodDao.selectDefualtMethod(member.getId(), null, "1");
        if (defualtMethod != null) {
            if (id.equals(defualtMethod.getId())) {
                return Result.fail("不能关闭默认收款方式");
            }
        }
        MemberPaymentMethodEntity paymentMethodEntity = new MemberPaymentMethodEntity();
        paymentMethodEntity.setId(id);
        paymentMethodEntity.setIsDefualt("1");
        this.memberPaymentMethodDao.updateById(paymentMethodEntity);
        if (defualtMethod != null) {
            defualtMethod.setIsDefualt("2");
            this.memberPaymentMethodDao.updateById(defualtMethod);
        }
        return Result.ok("操作成功");
    }
    @Override
    @Transactional
    public Result memberBindPhone(@Valid MemberBindPhoneDto memberBindPhoneDto) {
        //获取用户ID
@@ -1094,6 +1118,20 @@
        }
        return Result.ok(memberTeamVo);
    }
    @Override
    public Result findDefaultWay() {
        //获取用户ID
        Long memberId = LoginUserUtils.getAppLoginUser().getId();
        DefaultWayVo defaultWayVo = new DefaultWayVo();
        MemberPaymentMethodEntity defualtMethod = this.memberPaymentMethodDao.selectDefualtMethod(memberId, null, "1");
        if(ObjectUtil.isNotEmpty(defualtMethod)){
            String paymentType = defualtMethod.getPaymentType();
            defaultWayVo.setPaymentType(paymentType);
        }
        return Result.ok(defaultWayVo);
    }
}
src/main/java/com/xcong/excoin/modules/member/vo/DefaultWayVo.java
New file
@@ -0,0 +1,18 @@
package com.xcong.excoin.modules.member.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "DefaultWayVo", description = "接口返回类")
public class DefaultWayVo {
    /**
     * 类型 1-支付宝2-微信3-银行卡
     */
    @ApiModelProperty(value = "类型 1-支付宝2-微信3-银行卡")
    private String paymentType;
}
src/main/java/com/xcong/excoin/modules/otc/controller/OtcBlackListController.java
New file
@@ -0,0 +1,101 @@
package com.xcong.excoin.modules.otc.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xcong.excoin.common.LoginUserUtils;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.otc.dao.OtcBlackListDao;
import com.xcong.excoin.modules.otc.dao.OtcOrderDao;
import com.xcong.excoin.modules.otc.dto.AddBlackDto;
import com.xcong.excoin.modules.otc.dto.BlackListDto;
import com.xcong.excoin.modules.otc.entity.OtcBlackList;
import com.xcong.excoin.modules.otc.entity.OtcOrder;
import com.xcong.excoin.modules.otc.vo.BlackListVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@Validated
@RestController
@RequestMapping(value = "/api/black")
@Api(value = "OtcBlackListController", tags = "otc黑名单列表接口类")
public class OtcBlackListController {
    @Autowired
    private OtcBlackListDao otcBlackListDao;
    @Autowired
    private OtcOrderDao otcOrderDao;
    @ApiOperation(value = "添加黑名单")
    @PostMapping(value = "/add")
    public Result add(@RequestBody AddBlackDto addBlackDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcOrder otcOrder = otcOrderDao.selectById(addBlackDto.getId());
        if (otcOrder == null) {
            return Result.fail("订单不存在");
        }
        OtcBlackList isExist = otcBlackListDao.selectByMemberIdAndBlackMemberId(member.getId(), otcOrder.getEntrustMemberId());
        if (isExist != null) {
            return Result.fail("请勿重复拉黑");
        }
        if (member.getId().equals(otcOrder.getEntrustMemberId())) {
            return Result.fail("不能拉黑自己");
        }
        OtcBlackList otcBlackList = new OtcBlackList();
        otcBlackList.setMemberId(member.getId());
        otcBlackList.setBlackMemberId(otcOrder.getEntrustMemberId());
        otcBlackList.setReasons(addBlackDto.getReason());
        otcBlackListDao.insert(otcBlackList);
        return Result.ok("拉黑成功");
    }
    @ApiOperation(value = "黑名单列表")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = BlackListVo.class)
    })
    @PostMapping(value = "/blackList")
    public Result blackList(@RequestBody BlackListDto blackListDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        Page<BlackListVo> page = new Page<>(blackListDto.getPageNum(), blackListDto.getPageSize());
        IPage<BlackListVo> result = otcBlackListDao.selectBlackListInPage(member.getId(), page);
        return Result.ok(result.getRecords());
    }
    @ApiOperation(value = "删除黑名单")
    @PostMapping(value = "/del")
    public Result del(@RequestBody AddBlackDto addBlackDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        if (addBlackDto.getType() == null) {
            return Result.fail("参数错误");
        }
        if (addBlackDto.getType() == 1) {
            OtcOrder otcOrder = otcOrderDao.selectById(addBlackDto.getId());
            if (otcOrder == null) {
                return Result.fail("订单不存在");
            }
            OtcBlackList otcBlackList = otcBlackListDao.selectByMemberIdAndBlackMemberId(member.getId(), otcOrder.getEntrustMemberId());
            otcBlackListDao.deleteById(otcBlackList.getId());
        } else {
            otcBlackListDao.deleteById(addBlackDto.getId());
        }
        return Result.ok("解除成功");
    }
}
src/main/java/com/xcong/excoin/modules/otc/controller/OtcEntrustOrderController.java
New file
@@ -0,0 +1,122 @@
package com.xcong.excoin.modules.otc.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xcong.excoin.common.LoginUserUtils;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.otc.dao.OtcSettingDao;
import com.xcong.excoin.modules.otc.dto.EntrustOrderAddDto;
import com.xcong.excoin.modules.otc.dto.EntrustOrderListDto;
import com.xcong.excoin.modules.otc.entity.OtcEntrustOrder;
import com.xcong.excoin.modules.otc.entity.OtcSetting;
import com.xcong.excoin.modules.otc.service.OtcEntrustOrderService;
import com.xcong.excoin.modules.otc.vo.EntrustListInfoVo;
import com.xcong.excoin.modules.otc.vo.EntrustListVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.web3j.abi.datatypes.Int;
import javax.validation.Valid;
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/api/otcOrder")
@Validated
@Api(value = "OtcEntrustOrderController", tags = "otc委托订单接口类")
public class OtcEntrustOrderController {
    private final OtcEntrustOrderService otcEntrustOrderService;
    private final OtcSettingDao otcSettingDao;
    @ApiOperation(value = "添加otc委托单", notes = "添加otc委托单")
    @PostMapping(value = "/addEntrustOrder")
    public Result addEntrustOrder(@RequestBody EntrustOrderAddDto addDto) {
        otcEntrustOrderService.add(addDto);
        return Result.ok("添加成功");
    }
    @ApiOperation(value = "获取市商条件")
    @ApiResponses({
            @ApiResponse(code  = 200, message = "success", response = OtcSetting.class)
    })
    @GetMapping(value = "/findCondition")
    public Result findCondition() {
        OtcSetting setting = otcSettingDao.selectById(1L);
        return Result.ok(setting);
    }
    @ApiOperation(value = "编辑otc委托单", notes = "编辑otc委托单")
    @PostMapping(value = "/modifyEntrustOrder")
    public Result modifyEntrustOrder(@RequestBody EntrustOrderAddDto modifyDto) {
        otcEntrustOrderService.modify(modifyDto);
        return Result.ok("编辑成功");
    }
    @ApiOperation(value = "获取otc委托单列表", notes = "获取otc委托单列表")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = EntrustListVo.class)
    })
    @PostMapping(value = "/findEntrustOrderList")
    public Result findEntrustOrderList(@RequestBody EntrustOrderListDto orderListDto) {
        IPage<EntrustListVo> result = this.otcEntrustOrderService.findEntrustListInPage(orderListDto);
        return Result.ok(result.getRecords());
    }
    @ApiOperation(value = "获取我的委托单列表", notes = "获取我的委托单列表")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = EntrustListInfoVo.class)
    })
    @PostMapping(value = "/findOwnEntrustOrderList")
    public Result findOwnEntrustOrderList(@RequestBody EntrustOrderListDto orderListDto) {
        return Result.ok(otcEntrustOrderService.findOwnEntrustOrder(orderListDto));
    }
    @ApiOperation(value = "获取我的委托单详情")
    @GetMapping(value = "/findOwnOrderDetail/{id}")
    public Result findOwnOrderDetail(@PathVariable("id") Long id) {
        return otcEntrustOrderService.findEntrustOrderDetail(id);
    }
    @ApiOperation(value = "上/下线接口")
    @PostMapping(value = "/upOrDownList/{id}")
    public Result upOrDownList(@PathVariable("id") Long id) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcEntrustOrder otcEntrustOrder = this.otcEntrustOrderService.getById(id);
        if (otcEntrustOrder == null) {
            return Result.fail("数据不存在");
        }
        if (!member.getId().equals(otcEntrustOrder.getMemberId())) {
            return Result.fail("数据错误");
        }
        Integer status = otcEntrustOrder.getStatus();
        otcEntrustOrder = new OtcEntrustOrder();
        otcEntrustOrder.setId(id);
        if (status.equals(OtcEntrustOrder.LINE_DOWN)) {
            otcEntrustOrder.setStatus(OtcEntrustOrder.LINE_UP);
        } else {
            otcEntrustOrder.setStatus(OtcEntrustOrder.LINE_DOWN);
        }
        this.otcEntrustOrderService.updateById(otcEntrustOrder);
        return Result.ok("修改成功");
    }
    @ApiOperation(value = "撤销委托单")
    @PostMapping(value = "/cancelOrder/{id}")
    public Result cancelOrder(@PathVariable("id") Long id) {
        this.otcEntrustOrderService.cancelEntrustOrder(id);
        return Result.ok("撤销成功");
    }
}
src/main/java/com/xcong/excoin/modules/otc/controller/OtcMarketBussinessController.java
New file
@@ -0,0 +1,117 @@
package com.xcong.excoin.modules.otc.controller;
import com.xcong.excoin.common.LoginUserUtils;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.member.dao.MemberDao;
import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
import com.xcong.excoin.modules.otc.dto.MbAddDto;
import com.xcong.excoin.modules.otc.entity.OtcMarketBussiness;
import com.xcong.excoin.modules.otc.mapper.OtcMarketBussinessMapper;
import com.xcong.excoin.modules.otc.service.OtcEntrustOrderService;
import com.xcong.excoin.modules.otc.service.OtcMarketBussinessService;
import com.xcong.excoin.modules.otc.vo.ApplyConditionsVo;
import com.xcong.excoin.modules.otc.vo.MarketBussinessInfoVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
@Slf4j
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/api/marketBussiness")
@Api(value = "OtcMarketBussinessController", tags = "otc市商接口类")
public class OtcMarketBussinessController {
    private final OtcMarketBussinessService otcMarketBussinessService;
    private final MemberWalletCoinDao memberWalletCoinDao;
    private final MemberDao memberDao;
    @ApiOperation(value = "申请条件", notes = "申请条件")
    @ApiResponses({
            @ApiResponse(code = 200, message = "获取成功", response = ApplyConditionsVo.class)
    })
    @PostMapping(value = "/applyConditions")
    public Result applyConditions() {
        return otcMarketBussinessService.applyConditions();
    }
    @ApiOperation(value = "申请市商接口", notes = "申请市商接口")
    @PostMapping(value = "/applyMaketBussiness")
    public Result applyMarketBussiness() {
        otcMarketBussinessService.add();
        return Result.ok("申请成功, 等待审核");
    }
//    @ApiOperation(value = "modifyMarketBussiness", notes = "修改个人信息")
    @PostMapping(value = "/modifyMarketBussiness")
    public Result modifyMarketBussiness(@RequestBody MbAddDto mbAddDto) {
        if (mbAddDto.getId() == null) {
            return Result.fail("id不能为空");
        }
        OtcMarketBussiness mb = otcMarketBussinessService.getById(mbAddDto.getId());
        if (mb == null) {
            return Result.fail("市商不存在");
        }
        if (!mb.getStatus().equals(OtcMarketBussiness.CHECK_PASS)) {
            return Result.fail("暂不能修改信息");
        }
        OtcMarketBussiness otcMb = new OtcMarketBussiness();
        otcMb.setId(mbAddDto.getId());
//        otcMb.setNikename(mbAddDto.getNickname());
        otcMarketBussinessService.updateById(otcMb);
        return Result.ok("修改成功");
    }
    @ApiOperation(value = "findMarketBussinessStatus", notes = "获取市商申请状态接口")
    @GetMapping(value = "/findMarketBussinessStatus")
    public Result findMarketBussinessStatus() {
        return Result.ok("获取成功", otcMarketBussinessService.findMbStatus());
    }
    @ApiOperation(value = "获取市商信息", notes = "获取市商信息")
    @ApiResponses({
            @ApiResponse(code = 200, message = "获取成功", response = MarketBussinessInfoVo.class)
    })
    @GetMapping(value = "/findMbInfo/{id}")
    public Result findMbInfo(@PathVariable("id") Long id) {
        return this.otcMarketBussinessService.findMbInfo(id);
    }
    @ApiOperation(value = "修改姓名")
    @PostMapping(value = "/modifyName")
    public Result modifyName(@RequestBody MbAddDto mbAddDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        Long memberId = member.getId();
        member = new MemberEntity();
        member.setId(memberId);
        member.setName(mbAddDto.getNickname());
        memberDao.updateById(member);
        return Result.ok("修改成功");
    }
    @ApiOperation(value = "查询当前用户可用")
    @GetMapping(value = "/memberWallet")
    public Result memberWallet() {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        MemberWalletCoinEntity wallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(member.getId(), "USDT");
        return Result.ok(wallet.getAvailableBalance());
    }
}
src/main/java/com/xcong/excoin/modules/otc/controller/OtcMsgController.java
New file
@@ -0,0 +1,93 @@
package com.xcong.excoin.modules.otc.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.otc.dto.*;
import com.xcong.excoin.modules.otc.service.OtcMsgService;
import com.xcong.excoin.modules.otc.vo.ChatBoxVo;
import com.xcong.excoin.modules.otc.vo.ChatOrderVo;
import com.xcong.excoin.modules.otc.vo.MsgListVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@Validated
@RestController
@RequestMapping(value = "/api/otcMsg")
@RequiredArgsConstructor
@Api(value = "OtcMsgController", tags = "otc用户消息接口类")
public class OtcMsgController {
    private final OtcMsgService otcMsgService;
    /**
     * 获取对话列表
     */
    @ApiOperation(value = "获取对话列表")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = MsgListVo.class)
    })
    @PostMapping(value = "/getMsgList")
    public Result getMsgList(@RequestBody MsgListDto msgListDto) {
        IPage<MsgListVo> page = otcMsgService.getMsgList(msgListDto);
        return Result.ok(page.getRecords());
    }
    /**
     * 联系卖家或者联系买家
     */
    @ApiOperation(value = "联系卖家或者联系买家")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ChatBoxVo.class)
    })
    @PostMapping(value = "/getChatBoxConnect")
    public Result getChatBoxConnect(@RequestBody ConnectDto connectDto) {
        return otcMsgService.getChatBoxConnect(connectDto);
    }
    /**
     * 进入聊天框,获取聊天记录
     */
    @ApiOperation(value = "进入聊天框,获取聊天记录")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ChatBoxVo.class)
    })
    @PostMapping(value = "/getChatBox")
    public Result getChatBox(@RequestBody ChatBoxDto chatBoxDto) {
        return otcMsgService.getChatBox(chatBoxDto);
    }
    /**
     * 进入聊天框,获取聊天记录---获取未完成记录
     */
    @ApiOperation(value = "进入聊天框---获取未完成记录")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = ChatOrderVo.class)
    })
    @PostMapping(value = "/getChatOrder")
    public Result getChatOrder(@RequestBody ChatOrderDto chatOrderDto) {
        return otcMsgService.getChatOrder(chatOrderDto);
    }
    /**
     * 发送消息
     */
    @ApiOperation(value = "发送消息")
    @PostMapping(value = "/sendMsg")
    public Result sendMsg(@RequestBody SendMsgDto sendMsgDto) {
        return otcMsgService.sendMsg(sendMsgDto);
    }
}
src/main/java/com/xcong/excoin/modules/otc/controller/OtcOrderController.java
New file
@@ -0,0 +1,124 @@
package com.xcong.excoin.modules.otc.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xcong.excoin.common.LoginUserUtils;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.member.dao.MemberDao;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.otc.dao.OtcReturnMoneyDao;
import com.xcong.excoin.modules.otc.dto.*;
import com.xcong.excoin.modules.otc.service.OtcOrderService;
import com.xcong.excoin.modules.otc.vo.BuyOrderDetailVo;
import com.xcong.excoin.modules.otc.vo.OrderListVo;
import com.xcong.excoin.modules.otc.vo.SaleOrderDetailVo;
import com.xcong.excoin.modules.otc.vo.TeamVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Validated
@RestController
@RequestMapping(value = "/api/otcOrder")
@RequiredArgsConstructor
@Api(value = "OtcOrderController", tags = "otc用户订单接口类")
public class OtcOrderController {
    private final OtcOrderService otcOrderService;
    private final OtcReturnMoneyDao otcReturnMoneyDao;
    @ApiOperation(value = "我要购买")
    @PostMapping(value = "/buy")
    public Result buy(@RequestBody OtcOrderAddDto orderAddDto) {
        return otcOrderService.buyOrder(orderAddDto);
    }
    @ApiOperation(value = "我要出售")
    @PostMapping(value = "/sale")
    public Result sale(@RequestBody OtcOrderAddDto orderAddDto) {
        return otcOrderService.saleOrder(orderAddDto);
    }
    @ApiOperation(value = "用户订单列表")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = OrderListVo.class)
    })
    @PostMapping(value = "/orderList")
    public Result orderList(@RequestBody OrderListDto orderListDto) {
        IPage<OrderListVo> page = otcOrderService.findOrderListInPage(orderListDto);
        return Result.ok(page.getRecords());
    }
    @ApiOperation(value = "买单 - 订单详情")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = BuyOrderDetailVo.class)
    })
    @GetMapping(value = "/buyOrderDetail/{id}")
    public Result buyOrderDetail(@PathVariable("id") Long id) {
        return otcOrderService.findBuyOrderDetail(id);
    }
    @ApiOperation(value = "卖单 - 订单详情")
    @ApiResponses({
            @ApiResponse(code = 200, message = "success", response = SaleOrderDetailVo.class)
    })
    @GetMapping(value = "/saleOrderDetail/{id}")
    public Result saleOrderDetail(@PathVariable("id") Long id) {
        return otcOrderService.findSaleOrderDetail(id);
    }
    @ApiOperation(value = "已付款,请放币")
    @PostMapping(value = "/hasPay")
    public Result hasPay(@RequestBody HasPayDto hasPayDto) {
        otcOrderService.hasPay(hasPayDto);
        return Result.ok("操作成功");
    }
    @ApiOperation(value = "确认收款")
    @PostMapping(value = "/finishOrder/{id}")
    public Result finishOrder(@PathVariable("id") Long id) {
        otcOrderService.finishOrder(id);
        return Result.ok("操作成功");
    }
    @ApiOperation(value = "取消订单")
    @PostMapping(value = "/cancelUserOrder/{id}")
    public Result cancelUserOrder(@PathVariable("id") Long id) {
        otcOrderService.cancelOrder(id);
        return Result.ok("操作成功");
    }
    @ApiOperation(value = "申诉")
    @PostMapping(value = "/orderApeal")
    public Result orderApeal(@RequestBody OrderApealDto orderApealDto) {
        return otcOrderService.orderApeal(orderApealDto);
    }
    @ApiOperation(value = "获取我的团队")
    @PostMapping(value = "/findTeamList")
    public Result teamList(@RequestBody TeamDto teamDto) {
        Page<TeamVo> page = new Page<>(teamDto.getPageNum(), teamDto.getPageSize());
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        IPage<TeamVo> data = otcReturnMoneyDao.selectMyTeamAmountInPage(member.getInviteId(), member.getId(), page);
        BigDecimal totalAmount = otcReturnMoneyDao.selectTotalAmount(member.getId());
        Map<String, Object> result = new HashMap<>();
        result.put("totalCnt", data.getTotal());
        result.put("totalAmount", totalAmount == null ? BigDecimal.ZERO : totalAmount.setScale(4, BigDecimal.ROUND_DOWN));
        result.put("result", data.getRecords());
        return Result.ok(result);
    }
}
src/main/java/com/xcong/excoin/modules/otc/dao/OtcBlackListDao.java
New file
@@ -0,0 +1,19 @@
package com.xcong.excoin.modules.otc.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xcong.excoin.modules.otc.entity.OtcBlackList;
import com.xcong.excoin.modules.otc.vo.BlackListVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface OtcBlackListDao extends BaseMapper<OtcBlackList> {
    OtcBlackList selectByMemberIdAndBlackMemberId(@Param("memberId") Long memberId, @Param("blackMemberId") Long blackMemberId);
    IPage<BlackListVo> selectBlackListInPage(@Param("memberId") Long memberId, Page<BlackListVo> page);
    List<OtcBlackList> selectBlackListByMemberId(@Param("memberId") Long memberId);
}
src/main/java/com/xcong/excoin/modules/otc/dao/OtcEntrustOrderDao.java
New file
@@ -0,0 +1,24 @@
package com.xcong.excoin.modules.otc.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xcong.excoin.modules.otc.dto.EntrustOrderListDto;
import com.xcong.excoin.modules.otc.entity.OtcEntrustOrder;
import com.xcong.excoin.modules.otc.vo.EntrustListVo;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
import java.util.List;
public interface OtcEntrustOrderDao extends BaseMapper<OtcEntrustOrder> {
    IPage<EntrustListVo> selectEntrustListInPage(@Param("record") EntrustOrderListDto dto, Page<EntrustListVo> page);
    List<OtcEntrustOrder> selectEntrustOrderByOrderType(@Param("record") OtcEntrustOrder otcEntrustOrder);
    IPage<OtcEntrustOrder> selectOwnEntrustListInPage(@Param("record") OtcEntrustOrder otcEntrustOrder, Page<OtcEntrustOrder> page);
    int updateRemainAmount(@Param("id") Long id, @Param("amount") BigDecimal amount);
}
src/main/java/com/xcong/excoin/modules/otc/dao/OtcMarketBussinessDao.java
New file
@@ -0,0 +1,10 @@
package com.xcong.excoin.modules.otc.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xcong.excoin.modules.otc.entity.OtcMarketBussiness;
import org.apache.ibatis.annotations.Param;
public interface OtcMarketBussinessDao extends BaseMapper<OtcMarketBussiness> {
    OtcMarketBussiness selectMarketBussinessByMemberId(@Param("memberId") Long memberId);
}
src/main/java/com/xcong/excoin/modules/otc/dao/OtcMsgHistoryDao.java
New file
@@ -0,0 +1,14 @@
package com.xcong.excoin.modules.otc.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xcong.excoin.modules.otc.entity.OtcMsgHistoryEntity;
import com.xcong.excoin.modules.otc.vo.ChatBoxVo;
import org.apache.ibatis.annotations.Param;
public interface OtcMsgHistoryDao  extends BaseMapper<OtcMsgHistoryEntity> {
    IPage<ChatBoxVo> getChatBoxMsgList(Page<ChatBoxVo> page, @Param("record")OtcMsgHistoryEntity otcMsgHistoryEntity);
}
src/main/java/com/xcong/excoin/modules/otc/dao/OtcMsgUserListDao.java
New file
@@ -0,0 +1,19 @@
package com.xcong.excoin.modules.otc.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xcong.excoin.modules.otc.entity.OtcMsgUserListEntity;
import com.xcong.excoin.modules.otc.vo.MsgListVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface OtcMsgUserListDao extends BaseMapper<OtcMsgUserListEntity> {
    IPage<MsgListVo> getMsgList(@Param("record")OtcMsgUserListEntity otcMsgUserListEntity, Page<MsgListVo> page);
    List<OtcMsgUserListEntity> selectListByMemberIdAndTargetId(@Param("memberId")Long memberId, @Param("targetId")long targetId);
    OtcMsgUserListEntity selectChatListByToAndFrom(@Param("to") Long to, @Param("from") Long from);
}
src/main/java/com/xcong/excoin/modules/otc/dao/OtcOrderAppealDao.java
New file
@@ -0,0 +1,7 @@
package com.xcong.excoin.modules.otc.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xcong.excoin.modules.otc.entity.OtcOrderAppeal;
public interface OtcOrderAppealDao extends BaseMapper<OtcOrderAppeal> {
}
src/main/java/com/xcong/excoin/modules/otc/dao/OtcOrderDao.java
New file
@@ -0,0 +1,46 @@
package com.xcong.excoin.modules.otc.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xcong.excoin.modules.otc.entity.OtcOrder;
import com.xcong.excoin.modules.otc.vo.ChatOrderVo;
import com.xcong.excoin.modules.otc.vo.OrderListVo;
import org.apache.ibatis.annotations.Param;
import org.web3j.abi.datatypes.Int;
import java.math.BigDecimal;
import java.util.List;
public interface OtcOrderDao extends BaseMapper<OtcOrder> {
    List<OtcOrder> selectOrderListUnFinish(@Param("memberId") Long memberId, @Param("entrustOrderId") Long entrustOrderId);
    IPage<OrderListVo> selectOrdderListInPage(@Param("record") OtcOrder order, Page<OrderListVo> page);
    int updateOrderStatusByOrderNo(@Param("status") Integer status, @Param("payName") String payName, @Param("orderNo") String orderNo);
    OtcOrder selectOrderByOrderNoAndType(@Param("orderNo") String orderNo, @Param("orderType") String orderType);
    List<OtcOrder> selectOrderListWithStatusAndType(@Param("type") String orderType, @Param("status") Integer status);
    Integer selectMemberCntForEntrust(@Param("entrustMemberId") Long entrustMemberId);
    Integer selectTotalOrderCount(@Param("entrustMemberId") Long entrustMemberId, @Param("status") Integer status, @Param("type") String type);
    BigDecimal selectMemberAvgPayTime(@Param("memberId") Long memberId);
    BigDecimal selectMemberAvgCoinTime(@Param("memberId") Long memberId);
    List<OtcOrder> selectOrderListForUser(@Param("memberId") Long memberId, @Param("status") Integer status);
    BigDecimal selectOrderTotalAmount(@Param("memberId") Long memberId);
    List<ChatOrderVo> selectByMemberIdAndTargetId(@Param("memberId")Long memberId, @Param("targetId")long targetId);
    List<ChatOrderVo> selectOneByMemberIdAndTargetId(@Param("memberId")Long memberId, @Param("targetId")long targetId);
    int updateIsReturnByOrderNo(@Param("isReturn") Integer isReturn, @Param("orderNo") String orderNo);
    OtcOrder selectOrderUnEntrust(@Param("orderNo") String orderNo);
}
src/main/java/com/xcong/excoin/modules/otc/dao/OtcReturnMoneyDao.java
New file
@@ -0,0 +1,17 @@
package com.xcong.excoin.modules.otc.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xcong.excoin.modules.otc.entity.OtcReturnMoney;
import com.xcong.excoin.modules.otc.vo.TeamVo;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal;
public interface OtcReturnMoneyDao extends BaseMapper<OtcReturnMoney> {
    IPage<TeamVo> selectMyTeamAmountInPage(@Param("inviteId") String inviteId, @Param("memberId") Long memberId, Page<TeamVo> page);
    BigDecimal selectTotalAmount(@Param("memberId") Long memberId);
}
src/main/java/com/xcong/excoin/modules/otc/dao/OtcSettingDao.java
New file
@@ -0,0 +1,8 @@
package com.xcong.excoin.modules.otc.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xcong.excoin.modules.otc.entity.OtcSetting;
public interface OtcSettingDao extends BaseMapper<OtcSetting> {
}
src/main/java/com/xcong/excoin/modules/otc/dto/AddBlackDto.java
New file
@@ -0,0 +1,25 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "AddBlackDto", description = "拉黑/取消拉黑接口参数接受类")
public class AddBlackDto {
    @NotNull(message = "参数错误")
    @ApiModelProperty(value = "订单id/黑名单id")
    private Long id;
    @NotBlank(message = "参数错误")
    @ApiModelProperty(value = "1-订单 2-黑名单ID")
    private Integer type;
    @ApiModelProperty(value = "原因 - 删除不传")
    private String reason;
}
src/main/java/com/xcong/excoin/modules/otc/dto/BlackListDto.java
New file
@@ -0,0 +1,16 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "BlackListDto", description = "黑名单列表参数接收类")
public class BlackListDto {
    @ApiModelProperty(value = "页数")
    private Integer pageNum = 1;
    @ApiModelProperty(value = "条数")
    private Integer pageSize = 10;
}
src/main/java/com/xcong/excoin/modules/otc/dto/ChatBoxDto.java
New file
@@ -0,0 +1,22 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "ChatBoxDto", description = "参数接收类")
public class ChatBoxDto {
    @ApiModelProperty(value = "条数", example = "10")
    private Integer pageSize;
    @ApiModelProperty(value = "页码", example = "1")
    private Integer pageNum;
    @ApiModelProperty(value = "ID", example = "1")
    private long id;
    @ApiModelProperty(value = "目标ID", example = "1")
    private long targetId;
}
src/main/java/com/xcong/excoin/modules/otc/dto/ChatOrderDto.java
New file
@@ -0,0 +1,14 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "ChatOrderDto", description = "参数接收类")
public class ChatOrderDto {
    @ApiModelProperty(value = "目标ID", example = "1")
    private long targetId;
}
src/main/java/com/xcong/excoin/modules/otc/dto/ConnectDto.java
New file
@@ -0,0 +1,20 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "ConnectDto", description = "参数接收类")
public class ConnectDto {
    @ApiModelProperty(value = "条数", example = "10")
    private Integer pageSize;
    @ApiModelProperty(value = "页码", example = "1")
    private Integer pageNum;
    @ApiModelProperty(value = "目标ID", example = "1")
    private long targetId;
}
src/main/java/com/xcong/excoin/modules/otc/dto/EntrustOrderAddDto.java
New file
@@ -0,0 +1,38 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
@Data
@ApiModel(value = "EntrustOrderAddDto", description = "添加委托单接口参数接收类")
public class EntrustOrderAddDto {
    @ApiModelProperty(value = "id-编辑时传")
    private Long id;
    @NotBlank(message = "单价不能为空")
    @ApiModelProperty(value = "单价", example = "1")
    private BigDecimal unitPrice;
    @NotBlank(message = "数量不能为空")
    @ApiModelProperty(value = "数量", example = "1")
    private BigDecimal amount;
    @ApiModelProperty(value = "总额", example = "1")
    private BigDecimal totalAmount;
    @ApiModelProperty(value = "限额 - 最大值", example = "2")
    private BigDecimal max;
    @ApiModelProperty(value = "限额 - 最小值", example = "1")
    private BigDecimal min;
    @NotBlank(message = "委托单类型不能为空")
    @ApiModelProperty(value = "类型", example = "B/买-S/卖 编辑不传")
    private String type;
}
src/main/java/com/xcong/excoin/modules/otc/dto/EntrustOrderListDto.java
New file
@@ -0,0 +1,30 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@ApiModel(value = "EntrustOrderListDto", description = "委托单列表接口参数接收类")
public class EntrustOrderListDto {
    @NotNull
    @Min(1)
    @ApiModelProperty(value = "第几页", example = "1")
    private Integer pageNum;
    @NotNull
    @ApiModelProperty(value = "每页数量", example = "10")
    private Integer pageSize;
    @NotBlank
    @ApiModelProperty(value = "类型", example = "B-买 S-卖")
    private String type;
    @ApiModelProperty(hidden = true)
    private Long memberId;
}
src/main/java/com/xcong/excoin/modules/otc/dto/HasPayDto.java
New file
@@ -0,0 +1,16 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "HasPayDto", description = "已付款接口接收参数类")
public class HasPayDto {
    @ApiModelProperty(value = "订单ID", example = "1")
    private Long id;
    @ApiModelProperty(value = "姓名", example = "张三")
    private String name;
}
src/main/java/com/xcong/excoin/modules/otc/dto/MbAddDto.java
New file
@@ -0,0 +1,21 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
@ApiModel(value = "MbAddDto", description = "申请市商接口参数接收类")
public class MbAddDto {
    @ApiModelProperty(value = "id - 编辑时传")
    private Long id;
    @NotBlank(message = "昵称不能为空")
    @ApiModelProperty(value = "昵称", example = "123")
    private String nickname;
}
src/main/java/com/xcong/excoin/modules/otc/dto/MsgListDto.java
New file
@@ -0,0 +1,20 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "MsgListDto", description = "参数接收类")
public class MsgListDto {
    @ApiModelProperty(value = "条数", example = "10")
    private Integer pageSize;
    @ApiModelProperty(value = "页码", example = "1")
    private Integer pageNum;
    @ApiModelProperty(value = "昵称", example = "1")
    private String nickname;
}
src/main/java/com/xcong/excoin/modules/otc/dto/OrderApealDto.java
New file
@@ -0,0 +1,28 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(value = "OrderApealDto", description = "参数接收类")
public class OrderApealDto {
    @ApiModelProperty(value = "订单ID", example = "1")
    private Long orderId;
    /**
     * 申诉原因
     */
    @ApiModelProperty(value = "申诉原因", example = "1")
    private String reason;
    /**
     * 申诉内容
     */
    @ApiModelProperty(value = "申诉图片", example = "1")
    private List<String> content;
}
src/main/java/com/xcong/excoin/modules/otc/dto/OrderListDto.java
New file
@@ -0,0 +1,21 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "OtcOrderListDto", description = "订单列表请求参数类")
public class OrderListDto {
    @ApiModelProperty(value = "条数", example = "10")
    private Integer pageSize;
    @ApiModelProperty(value = "页码", example = "1")
    private Integer pageNum;
    @ApiModelProperty(value = "状态 1-未完成 2-已完成 3-已取消", example = "1")
    private Integer status;
}
src/main/java/com/xcong/excoin/modules/otc/dto/OtcOrderAddDto.java
New file
@@ -0,0 +1,29 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
@ApiModel(value = "OtcOrderAddDto", description = "提交订单接口参数接收类")
public class OtcOrderAddDto {
    @NotNull
    @ApiModelProperty(value = "购买USDT数量", example = "120.00")
    private BigDecimal usdtAmount;
    @NotNull
    @ApiModelProperty(value = "CNY金额", example = "120.00")
    private BigDecimal cnyAmount;
    @NotNull
    @ApiModelProperty(value = "委托单ID", example = "1")
    private Long id;
    @ApiModelProperty(value = "资金密码 -- 用户出售USDT使用", example = "123456")
    private String password;
}
src/main/java/com/xcong/excoin/modules/otc/dto/SendMsgDto.java
New file
@@ -0,0 +1,22 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "SendMsgDto", description = "参数接收类")
public class SendMsgDto {
    @ApiModelProperty(value = "目标用户ID")
    private long targetId;
    //消息
    @ApiModelProperty(value = "消息")
    private String msg;
    //消息类型 1-文本2-图片
    @ApiModelProperty(value = "消息类型 1-文本2-图片")
    private Integer msgType;
}
src/main/java/com/xcong/excoin/modules/otc/dto/TeamDto.java
New file
@@ -0,0 +1,15 @@
package com.xcong.excoin.modules.otc.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class TeamDto {
    @ApiModelProperty(value = "条数", example = "10")
    private Integer pageSize;
    @ApiModelProperty(value = "页码", example = "1")
    private Integer pageNum;
}
src/main/java/com/xcong/excoin/modules/otc/entity/OtcBlackList.java
New file
@@ -0,0 +1,17 @@
package com.xcong.excoin.modules.otc.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xcong.excoin.common.system.base.BaseEntity;
import lombok.Data;
@Data
@TableName("otc_black_list")
public class OtcBlackList extends BaseEntity {
    private Long memberId;
    private Long blackMemberId;
    private String reasons;
}
src/main/java/com/xcong/excoin/modules/otc/entity/OtcEntrustOrder.java
New file
@@ -0,0 +1,79 @@
package com.xcong.excoin.modules.otc.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xcong.excoin.common.system.base.BaseEntity;
import lombok.Data;
import java.math.BigDecimal;
@Data
@TableName("otc_entrust_order")
public class OtcEntrustOrder extends BaseEntity {
    private Long memberId;
    private Long mbId;
    /**
     * 委托单号
     */
    private String entrustOrderNo;
    /**
     * 单价
     */
    private BigDecimal unitPrice;
    /**
     * 数量
     */
    private BigDecimal coinAmount;
    /**
     * 剩余数量
     */
    private BigDecimal remainCoinAmount;
    /**
     * 限额
     */
    private BigDecimal limitMinAmount;
    /**
     * 限额
     */
    private BigDecimal limitMaxAmount;
    /**
     * 委托总金额
     */
    private BigDecimal totalAmount;
    /**
     * 委托单类型 B-买 S-卖
     */
    private String orderType;
    public static final String ORDER_TYPE_B = "B";
    public static final String ORDER_TYPE_S = "S";
    /**
     * 1-上线 2-下线 3-撤销
     */
    private Integer status;
    public static final Integer LINE_UP = 1;
    public static final Integer LINE_DOWN = 2;
    public static final Integer LINE_CANCEL = 3;
    /**
     * 是否市商 1-是 2-否
     */
    private Integer isMb;
    public static final Integer IS_MB_Y = 1;
    public static final Integer IS_MB_N = 2;
    @TableField(exist = false)
    private String payType;
    @TableField(exist = false)
    private Integer isDefualt;
}
src/main/java/com/xcong/excoin/modules/otc/entity/OtcMarketBussiness.java
New file
@@ -0,0 +1,60 @@
package com.xcong.excoin.modules.otc.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xcong.excoin.common.system.base.BaseEntity;
import lombok.Data;
import java.math.BigDecimal;
@Data
@TableName("otc_market_bussiness")
public class OtcMarketBussiness extends BaseEntity {
    private Long memberId;
    private String nikename;
    private String declaration;
    /**
     * 1-待审核2-审核通过3-审核拒绝
     */
    private Integer status;
    public static final Integer CHECK_WAIT = 1;
    public static final Integer CHECK_PASS = 2;
    public static final Integer CHECK_REFUSE = 3;
    private Integer buyCnt;
    private Integer totalOrderCnt;
    private BigDecimal finishRatio;
    private Integer avgPayTime;
    private Integer avgCoinTime;
    /**
     * 待回款
     */
    private BigDecimal waitBackMoney;
    /**
     * 已回款
     */
    private BigDecimal hasBackMoney;
    /**
     * 卖单数
     */
    private Integer saleOrderCnt;
    private BigDecimal saleFinishRatio;
    /**
     * 买单数
     */
    private Integer buyOrderCnt;
    private Integer saleTotalCnt;
}
src/main/java/com/xcong/excoin/modules/otc/entity/OtcMsgHistoryEntity.java
New file
@@ -0,0 +1,30 @@
package com.xcong.excoin.modules.otc.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xcong.excoin.common.system.base.BaseEntity;
import lombok.Data;
//历史消息
@Data
@TableName("otc_msg_history")
public class OtcMsgHistoryEntity extends BaseEntity {
    //用户ID
    private long memberId;
    //发送方
    private long fromMemberId;
    //对方用户ID
    private long targetId;
    //消息
    private String msg;
    //消息类型 1-文本2-图片
    private Integer msgType;
    //是不是memberId发的消息 1:是 2:否
    private Integer isSelf;
    public static final Integer ISSELF_ONE = 1;
    public static final Integer ISSELF_TWO = 2;
}
src/main/java/com/xcong/excoin/modules/otc/entity/OtcMsgUserListEntity.java
New file
@@ -0,0 +1,34 @@
package com.xcong.excoin.modules.otc.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xcong.excoin.common.system.base.BaseEntity;
import lombok.Data;
import java.util.Date;
//用户消息列表
@Data
@TableName("otc_msg_user_list")
public class OtcMsgUserListEntity  extends BaseEntity {
    //用户ID
    private long memberId;
    //对方用户ID
    private long targetId;
    //是否已读 1:未读 2:已读
    private Integer isRead;
    public static final Integer ISREAD_ONE = 1;
    public static final Integer ISREAD_TWO = 2;
    //最后聊天时间
    private Date lastMsgTime;
    @TableField(exist = false)
    private String nickname;
}
src/main/java/com/xcong/excoin/modules/otc/entity/OtcOrder.java
New file
@@ -0,0 +1,96 @@
package com.xcong.excoin.modules.otc.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xcong.excoin.common.system.base.BaseEntity;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@TableName("otc_order")
public class OtcOrder extends BaseEntity {
    private Long memberId;
    /**
     * 订单编号
     */
    private String orderNo;
    /**
     * 单价
     */
    private BigDecimal unitPrice;
    /**
     * 数量
     */
    private BigDecimal coinAmount;
    /**
     * 总额
     */
    private BigDecimal totalAmount;
    /**
     * 订单状态 1-已提交未付款2-已付款3-已完成
     */
    private Integer status;
    public static final Integer STATUS_SUBMIT = 1;
    public static final Integer STATUS_PAY = 2;
    public static final Integer STATUS_FINISH = 3;
    public static final Integer STATUS_CANCEL = 4;
    /**
     * 付款时间
     */
    private Date payTime;
    /**
     * 完成时间
     */
    private Date finishTime;
    /**
     * 委托单ID
     */
    private Long entrustOrderId;
    private Long mbId;
    /**
     * 支付市商ID
     */
    private Long payMbId;
    /**
     * 付款人姓名
     */
    private String payName;
    /**
     * 委托单用户ID
     */
    private Long entrustMemberId;
    /**
     * 订单类型 B-买 S-卖
     */
    private String orderType;
    /**
     * 对面的用户ID
     */
    private Long oppositeMemberId;
    private String bankName;
    private String bankNo;
    private String cardName;
    private String payType;
    private Integer isReturn;
}
src/main/java/com/xcong/excoin/modules/otc/entity/OtcOrderAppeal.java
New file
@@ -0,0 +1,31 @@
package com.xcong.excoin.modules.otc.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xcong.excoin.common.system.base.BaseEntity;
import lombok.Data;
@Data
@TableName("otc_order_appeal")
public class OtcOrderAppeal extends BaseEntity {
    private Long memberId;
    private Long orderId;
    /**
     * 申诉原因
     */
    private String reason;
    /**
     * 申诉内容
     */
    private String content;
    //申诉状态  1:待处理 2:处理中 3:已处理
    private Integer status;
    public static final Integer STATUS_ONE = 1;
    public static final Integer STATUS_TWO = 2;
    public static final Integer STATUS_THREE = 3;
}
src/main/java/com/xcong/excoin/modules/otc/entity/OtcReturnMoney.java
New file
@@ -0,0 +1,22 @@
package com.xcong.excoin.modules.otc.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xcong.excoin.common.system.base.BaseEntity;
import lombok.Data;
import java.math.BigDecimal;
@Data
@TableName("otc_return_money")
public class OtcReturnMoney extends BaseEntity {
    private String orderNo;
    private Long toMemberId;
    private Long fromMemberId;
    private BigDecimal amount;
}
src/main/java/com/xcong/excoin/modules/otc/entity/OtcSetting.java
New file
@@ -0,0 +1,22 @@
package com.xcong.excoin.modules.otc.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.web3j.abi.datatypes.Int;
import java.math.BigDecimal;
@Data
@TableName("otc_setting")
public class OtcSetting {
    private Long id;
    private Integer orderNum;
    private BigDecimal completionRate;
    private BigDecimal totalAmount;
    private Integer cancellNum;
}
src/main/java/com/xcong/excoin/modules/otc/mapper/OtcEntrustOrderMapper.java
New file
@@ -0,0 +1,39 @@
package com.xcong.excoin.modules.otc.mapper;
import com.xcong.excoin.modules.otc.dto.EntrustOrderAddDto;
import com.xcong.excoin.modules.otc.entity.OtcEntrustOrder;
import com.xcong.excoin.modules.otc.vo.EntrustListInfoVo;
import com.xcong.excoin.modules.otc.vo.EntrustOrderDetailVo;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public abstract class OtcEntrustOrderMapper {
    public static OtcEntrustOrderMapper INSTANCE = Mappers.getMapper(OtcEntrustOrderMapper.class);
    @Mapping(target = "coinAmount", source = "amount")
    @Mapping(target = "limitMinAmount", source = "min")
    @Mapping(target = "limitMaxAmount", source = "max")
    @Mapping(target = "orderType", source = "type")
    public abstract OtcEntrustOrder entrustOrderDtoToEntity(EntrustOrderAddDto entrustOrderAddDto);
    @Mapping(target = "min", source = "limitMinAmount")
    @Mapping(target = "max", source = "limitMaxAmount")
    @Mapping(target = "amount", source = "coinAmount")
    @Mapping(target = "remainAmount", source = "remainCoinAmount")
    public abstract EntrustListInfoVo entityToListInfoVo(OtcEntrustOrder otcEntrustOrder);
    public abstract List<EntrustListInfoVo> entrustToListInfoVoList(List<OtcEntrustOrder> list);
    @Mapping(target = "min", source = "limitMinAmount")
    @Mapping(target = "max", source = "limitMaxAmount")
    @Mapping(target = "amount", source = "coinAmount")
    @Mapping(target = "remainAmount", source = "remainCoinAmount")
    @Mapping(target = "orderNo", source = "entrustOrderNo")
    public abstract EntrustOrderDetailVo entityToOrderDetail(OtcEntrustOrder order);
}
src/main/java/com/xcong/excoin/modules/otc/mapper/OtcMarketBussinessMapper.java
New file
@@ -0,0 +1,14 @@
package com.xcong.excoin.modules.otc.mapper;
import com.xcong.excoin.modules.otc.entity.OtcMarketBussiness;
import com.xcong.excoin.modules.otc.vo.MarketBussinessInfoVo;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@Mapper
public abstract class OtcMarketBussinessMapper {
    public static OtcMarketBussinessMapper INSTANCE = Mappers.getMapper(OtcMarketBussinessMapper.class);
    public abstract MarketBussinessInfoVo entityToVo(OtcMarketBussiness otcMarketBussiness);
}
src/main/java/com/xcong/excoin/modules/otc/service/OtcEntrustOrderService.java
New file
@@ -0,0 +1,28 @@
package com.xcong.excoin.modules.otc.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.otc.dto.EntrustOrderAddDto;
import com.xcong.excoin.modules.otc.dto.EntrustOrderListDto;
import com.xcong.excoin.modules.otc.entity.OtcEntrustOrder;
import com.xcong.excoin.modules.otc.vo.EntrustListInfoVo;
import com.xcong.excoin.modules.otc.vo.EntrustListVo;
import java.util.List;
public interface OtcEntrustOrderService extends IService<OtcEntrustOrder> {
    void add(EntrustOrderAddDto addDto);
    void modify(EntrustOrderAddDto modifyDto);
    IPage<EntrustListVo> findEntrustListInPage(EntrustOrderListDto dto);
    List<EntrustListInfoVo> findOwnEntrustOrder(EntrustOrderListDto orderListDto);
    void cancelEntrustOrder(Long id);
    Result findEntrustOrderDetail(Long id);
}
src/main/java/com/xcong/excoin/modules/otc/service/OtcMarketBussinessService.java
New file
@@ -0,0 +1,17 @@
package com.xcong.excoin.modules.otc.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.otc.dto.MbAddDto;
import com.xcong.excoin.modules.otc.entity.OtcMarketBussiness;
public interface OtcMarketBussinessService extends IService<OtcMarketBussiness> {
    void add();
    Integer findMbStatus();
    Result findMbInfo(Long id);
    Result applyConditions();
}
src/main/java/com/xcong/excoin/modules/otc/service/OtcMsgService.java
New file
@@ -0,0 +1,22 @@
package com.xcong.excoin.modules.otc.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.otc.dto.*;
import com.xcong.excoin.modules.otc.entity.OtcMsgUserListEntity;
import com.xcong.excoin.modules.otc.vo.ChatBoxVo;
import com.xcong.excoin.modules.otc.vo.MsgListVo;
public interface OtcMsgService extends IService<OtcMsgUserListEntity> {
    IPage<MsgListVo> getMsgList(MsgListDto msgListDto);
    Result getChatBox(ChatBoxDto chatBoxDto);
    Result sendMsg(SendMsgDto sendMsgDto);
    Result getChatBoxConnect(ConnectDto connectDto);
    Result getChatOrder(ChatOrderDto chatOrderDto);
}
src/main/java/com/xcong/excoin/modules/otc/service/OtcOrderAppealService.java
New file
@@ -0,0 +1,8 @@
package com.xcong.excoin.modules.otc.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xcong.excoin.common.system.base.IBaseService;
import com.xcong.excoin.modules.otc.entity.OtcOrderAppeal;
public interface OtcOrderAppealService extends IService<OtcOrderAppeal> {
}
src/main/java/com/xcong/excoin/modules/otc/service/OtcOrderService.java
New file
@@ -0,0 +1,32 @@
package com.xcong.excoin.modules.otc.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.otc.dto.HasPayDto;
import com.xcong.excoin.modules.otc.dto.OrderApealDto;
import com.xcong.excoin.modules.otc.dto.OrderListDto;
import com.xcong.excoin.modules.otc.dto.OtcOrderAddDto;
import com.xcong.excoin.modules.otc.entity.OtcOrder;
import com.xcong.excoin.modules.otc.vo.OrderListVo;
public interface OtcOrderService extends IService<OtcOrder> {
    Result buyOrder(OtcOrderAddDto orderAddDto);
    Result saleOrder(OtcOrderAddDto orderAddDto);
    IPage<OrderListVo> findOrderListInPage(OrderListDto orderListDto);
    void hasPay(HasPayDto hasPayDto);
    void finishOrder(Long id);
    Result findBuyOrderDetail(Long id);
    Result findSaleOrderDetail(Long id);
    void cancelOrder(Long id);
    Result orderApeal(OrderApealDto orderApealDto);
}
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcEntrustOrderServiceImpl.java
New file
@@ -0,0 +1,230 @@
package com.xcong.excoin.modules.otc.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xcong.excoin.common.LoginUserUtils;
import com.xcong.excoin.common.exception.GlobalException;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.common.system.service.CommonService;
import com.xcong.excoin.modules.member.dao.MemberAuthenticationDao;
import com.xcong.excoin.modules.member.dao.MemberDao;
import com.xcong.excoin.modules.member.dao.MemberPaymentMethodDao;
import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.member.entity.MemberPaymentMethodEntity;
import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
import com.xcong.excoin.modules.otc.dao.OtcBlackListDao;
import com.xcong.excoin.modules.otc.dao.OtcMarketBussinessDao;
import com.xcong.excoin.modules.otc.dao.OtcOrderDao;
import com.xcong.excoin.modules.otc.dto.EntrustOrderAddDto;
import com.xcong.excoin.modules.otc.dto.EntrustOrderListDto;
import com.xcong.excoin.modules.otc.entity.OtcBlackList;
import com.xcong.excoin.modules.otc.entity.OtcEntrustOrder;
import com.xcong.excoin.modules.otc.dao.OtcEntrustOrderDao;
import com.xcong.excoin.modules.otc.entity.OtcMarketBussiness;
import com.xcong.excoin.modules.otc.entity.OtcOrder;
import com.xcong.excoin.modules.otc.mapper.OtcEntrustOrderMapper;
import com.xcong.excoin.modules.otc.service.OtcEntrustOrderService;
import com.xcong.excoin.modules.otc.vo.EntrustListInfoVo;
import com.xcong.excoin.modules.otc.vo.EntrustListVo;
import com.xcong.excoin.modules.otc.vo.EntrustOrderDetailVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import netscape.javascript.JSObject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class OtcEntrustOrderServiceImpl extends ServiceImpl<OtcEntrustOrderDao, OtcEntrustOrder> implements OtcEntrustOrderService {
    private final MemberDao memberDao;
    private final MemberPaymentMethodDao memberPaymentMethodDao;
    private final OtcMarketBussinessDao otcMarketBussinessDao;
    private final MemberWalletCoinDao memberWalletCoinDao;
    private final OtcOrderDao otcOrderDao;
    private final CommonService commonService;
    private final OtcBlackListDao otcBlackListDao;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(EntrustOrderAddDto addDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcEntrustOrder otcEntrustOrder = OtcEntrustOrderMapper.INSTANCE.entrustOrderDtoToEntity(addDto);
        otcEntrustOrder.setMemberId(member.getId());
        member = memberDao.selectById(member.getId());
        if (!MemberEntity.CERTIFY_STATUS_Y.equals(member.getCertifyStatus())) {
            throw new GlobalException("未实名认证");
        }
        List<MemberPaymentMethodEntity> payments = memberPaymentMethodDao.selectByMemberId(member.getId());
        if (CollUtil.isEmpty(payments)) {
            throw new GlobalException("未绑定收款方式");
        }
        BigDecimal totalAmount = addDto.getUnitPrice().multiply(addDto.getAmount());
        otcEntrustOrder.setTotalAmount(totalAmount);
        if (totalAmount.compareTo(addDto.getMax()) < 0) {
            throw new GlobalException("最大限额应小于总金额");
        }
        if (OtcEntrustOrder.ORDER_TYPE_S.equals(addDto.getType())) {
            MemberWalletCoinEntity coinWallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(member.getId(), "USDT");
//            BigDecimal multiply = addDto.getUnitPrice().multiply(coinWallet.getAvailableBalance());
            if(coinWallet.getAvailableBalance().compareTo(addDto.getAmount()) < 0) {
                throw new GlobalException("可用金额不足");
            }
            memberWalletCoinDao.updateFrozenBalance(member.getId(), coinWallet.getId(), addDto.getAmount());
        }
        if (!MemberEntity.IS_TRADER_Y.equals(member.getIsTrader())) {
            throw new GlobalException("不是市商");
        }
        if (member.getIsTrader() == 2) {
            otcEntrustOrder.setIsMb(OtcEntrustOrder.IS_MB_N);
        } else {
            otcEntrustOrder.setIsMb(OtcEntrustOrder.IS_MB_Y);
        }
        otcEntrustOrder.setRemainCoinAmount(addDto.getAmount());
        otcEntrustOrder.setStatus(OtcEntrustOrder.LINE_UP);
        otcEntrustOrder.setEntrustOrderNo(commonService.generateOrderNo(member.getId()));
        otcEntrustOrder.setId(null);
        this.baseMapper.insert(otcEntrustOrder);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modify(EntrustOrderAddDto modifyDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcEntrustOrder otcEntrustOrder = OtcEntrustOrderMapper.INSTANCE.entrustOrderDtoToEntity(modifyDto);
        otcEntrustOrder.setMemberId(member.getId());
        otcEntrustOrder.setRemainCoinAmount(modifyDto.getAmount());
        otcEntrustOrder.setStatus(OtcEntrustOrder.LINE_UP);
        List<OtcOrder> orders = otcOrderDao.selectOrderListUnFinish(member.getId(), otcEntrustOrder.getId());
        if (CollUtil.isNotEmpty(orders)) {
            throw new GlobalException("存在未完成的订单, 无法编辑");
        }
        OtcEntrustOrder prevEntity = this.baseMapper.selectById(modifyDto.getId());
        if (prevEntity == null) {
            throw new GlobalException("参数错误");
        }
        if (!prevEntity.getOrderType().equals(modifyDto.getType())) {
            throw new GlobalException("类型错误");
        }
        if (member.getIsTrader() == 2) {
            otcEntrustOrder.setIsMb(OtcEntrustOrder.IS_MB_N);
        } else {
            otcEntrustOrder.setIsMb(OtcEntrustOrder.IS_MB_Y);
        }
        BigDecimal totalAmount = modifyDto.getUnitPrice().multiply(modifyDto.getAmount());
        otcEntrustOrder.setTotalAmount(totalAmount);
        if (OtcEntrustOrder.ORDER_TYPE_S.equals(modifyDto.getType())) {
            MemberWalletCoinEntity coinWallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(member.getId(), "USDT");
            coinWallet.setAvailableBalance(coinWallet.getAvailableBalance().add(coinWallet.getFrozenBalance()));
            if(coinWallet.getAvailableBalance().compareTo(totalAmount) < 0) {
                throw new GlobalException("可用金额不足");
            }
            coinWallet.setAvailableBalance(coinWallet.getAvailableBalance().subtract(totalAmount));
            coinWallet.setFrozenBalance(totalAmount);
            memberWalletCoinDao.updateById(coinWallet);
        }
        this.baseMapper.updateById(otcEntrustOrder);
    }
    @Override
    public IPage<EntrustListVo> findEntrustListInPage(EntrustOrderListDto dto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        Page<EntrustListVo> page = new Page<>(dto.getPageNum(), dto.getPageSize());
//        List<OtcBlackList> blackLists = otcBlackListDao.selectBlackListByMemberId(member.getId());
//        if (CollUtil.isNotEmpty(blackLists)) {
            dto.setMemberId(member.getId());
//        }
        return this.baseMapper.selectEntrustListInPage(dto, page);
    }
    @Override
    public List<EntrustListInfoVo> findOwnEntrustOrder(EntrustOrderListDto orderListDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcEntrustOrder query = new OtcEntrustOrder();
        query.setStatus(3);
        query.setMemberId(member.getId());
        Page<OtcEntrustOrder> page = new Page<>(orderListDto.getPageNum(), orderListDto.getPageSize());
        IPage<OtcEntrustOrder> result = this.baseMapper.selectOwnEntrustListInPage(query, page);
        return OtcEntrustOrderMapper.INSTANCE.entrustToListInfoVoList(result.getRecords());
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelEntrustOrder(Long id) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcEntrustOrder otcEntrustOrder = this.baseMapper.selectById(id);
        if (otcEntrustOrder == null) {
            throw new GlobalException("参数错误");
        }
        if (OtcEntrustOrder.LINE_CANCEL.equals(otcEntrustOrder.getStatus())) {
            throw new GlobalException("请勿重复撤销");
        }
        List<OtcOrder> orders = otcOrderDao.selectOrderListUnFinish(member.getId(), otcEntrustOrder.getId());
        if (CollUtil.isNotEmpty(orders)) {
            throw new GlobalException("存在未完成的订单, 无法撤销");
        }
        if (OtcEntrustOrder.ORDER_TYPE_S.equals(otcEntrustOrder.getOrderType())) {
            MemberWalletCoinEntity wallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(member.getId(), "USDT");
            memberWalletCoinDao.subFrozenBalance(member.getId(), wallet.getId(), otcEntrustOrder.getRemainCoinAmount());
        }
        otcEntrustOrder = new OtcEntrustOrder();
        otcEntrustOrder.setId(id);
        otcEntrustOrder.setStatus(OtcEntrustOrder.LINE_CANCEL);
        this.baseMapper.updateById(otcEntrustOrder);
    }
    @Override
    public Result findEntrustOrderDetail(Long id) {
        OtcEntrustOrder otcEntrustOrder = this.baseMapper.selectById(id);
        if (otcEntrustOrder == null) {
            return Result.fail("参数错误");
        }
        MemberPaymentMethodEntity defualtMethod = memberPaymentMethodDao.selectDefualtMethod(otcEntrustOrder.getMemberId(), null, "1");
        MemberEntity member = memberDao.selectById(otcEntrustOrder.getMemberId());
        OtcMarketBussiness mb = otcMarketBussinessDao.selectMarketBussinessByMemberId(member.getId());
        EntrustOrderDetailVo detail = OtcEntrustOrderMapper.INSTANCE.entityToOrderDetail(otcEntrustOrder);
        detail.setName(member.getName());
        if (OtcEntrustOrder.ORDER_TYPE_S.equals(otcEntrustOrder.getOrderType())) {
            detail.setOrderCnt(mb.getSaleOrderCnt());
            detail.setFinishRatio(mb.getSaleFinishRatio());
        } else {
            detail.setOrderCnt(mb.getBuyOrderCnt());
            detail.setFinishRatio(mb.getFinishRatio());
        }
        detail.setPayType(defualtMethod.getPaymentType());
        return Result.ok(detail);
    }
}
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcMarketBussinessServiceImpl.java
New file
@@ -0,0 +1,180 @@
package com.xcong.excoin.modules.otc.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xcong.excoin.common.LoginUserUtils;
import com.xcong.excoin.common.exception.GlobalException;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.member.dao.MemberDao;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.otc.dao.OtcEntrustOrderDao;
import com.xcong.excoin.modules.otc.dao.OtcMarketBussinessDao;
import com.xcong.excoin.modules.otc.dao.OtcOrderDao;
import com.xcong.excoin.modules.otc.dao.OtcSettingDao;
import com.xcong.excoin.modules.otc.dto.MbAddDto;
import com.xcong.excoin.modules.otc.entity.OtcEntrustOrder;
import com.xcong.excoin.modules.otc.entity.OtcMarketBussiness;
import com.xcong.excoin.modules.otc.entity.OtcOrder;
import com.xcong.excoin.modules.otc.entity.OtcSetting;
import com.xcong.excoin.modules.otc.mapper.OtcEntrustOrderMapper;
import com.xcong.excoin.modules.otc.mapper.OtcMarketBussinessMapper;
import com.xcong.excoin.modules.otc.service.OtcMarketBussinessService;
import com.xcong.excoin.modules.otc.vo.ApplyConditionsVo;
import com.xcong.excoin.modules.otc.vo.EntrustListInfoVo;
import com.xcong.excoin.modules.otc.vo.MarketBussinessInfoVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
@Service
@RequiredArgsConstructor
public class OtcMarketBussinessServiceImpl extends ServiceImpl<OtcMarketBussinessDao, OtcMarketBussiness> implements OtcMarketBussinessService {
    private final OtcEntrustOrderDao otcEntrustOrderDao;
    private final MemberDao memberDao;
    private final OtcSettingDao otcSettingDao;
    private final OtcOrderDao otcOrderDao;
    @Override
    public void add() {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        member = memberDao.selectById(member.getId());
//        long memberId = 444L;
//        MemberEntity member = memberDao.selectById(memberId);
        if (MemberEntity.IS_TRADER_Y.equals(member.getIsTrader())) {
            throw new GlobalException("已经是市商");
        }
        OtcSetting setting = otcSettingDao.selectById(1L);
        // 所有已完成订单
        List<OtcOrder> finishOrders = otcOrderDao.selectOrderListForUser(member.getId(), 3);
        if (CollUtil.isEmpty(finishOrders) || setting.getOrderNum() > finishOrders.size()) {
            throw new GlobalException("条件未达标");
        }
        List<OtcOrder> allOrders = otcOrderDao.selectOrderListForUser(member.getId(), null);
        if (CollUtil.isNotEmpty(allOrders)) {
            BigDecimal finishRatio = BigDecimal.valueOf(finishOrders.size()).divide(BigDecimal.valueOf(allOrders.size()), 4, BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(100));
            if (setting.getCompletionRate().compareTo(finishRatio) > 0) {
                throw new GlobalException("条件未达标");
            }
        }
        BigDecimal totalAmount = otcOrderDao.selectOrderTotalAmount(member.getId());
        if (setting.getTotalAmount().compareTo(totalAmount) > 0) {
            throw new GlobalException("条件未达标");
        }
        OtcMarketBussiness mb = this.baseMapper.selectMarketBussinessByMemberId(member.getId());
        OtcMarketBussiness otcMb = new OtcMarketBussiness();
        if (mb != null) {
            if (OtcMarketBussiness.CHECK_PASS.equals(mb.getStatus()) || OtcMarketBussiness.CHECK_WAIT.equals(mb.getStatus())) {
                throw new GlobalException("已经是市商或正在审核");
            }
            otcMb = mb;
            otcMb.setStatus(OtcMarketBussiness.CHECK_WAIT);
            this.baseMapper.updateById(otcMb);
        } else {
            otcMb.setMemberId(member.getId());
            otcMb.setAvgCoinTime(0);
            otcMb.setAvgPayTime(0);
            otcMb.setTotalOrderCnt(0);
            otcMb.setBuyCnt(0);
            otcMb.setFinishRatio(BigDecimal.ZERO);
            otcMb.setStatus(OtcMarketBussiness.CHECK_WAIT);
            this.baseMapper.insert(otcMb);
        }
    }
    @Override
    public Integer findMbStatus() {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcMarketBussiness mb = this.baseMapper.selectMarketBussinessByMemberId(member.getId());
        if (mb == null) {
            return 0;
        }
        return mb.getStatus();
    }
    @Override
    public Result findMbInfo(Long id) {
        OtcMarketBussiness mb = this.baseMapper.selectById(id);
        if (mb == null) {
            return Result.fail("未找到对应信息");
        }
        MarketBussinessInfoVo mbVo = OtcMarketBussinessMapper.INSTANCE.entityToVo(mb);
        mbVo.setTotalOrderCnt(mb.getTotalOrderCnt() + mb.getSaleTotalCnt());
        mbVo.setFinishRatio(mb.getFinishRatio().add(mb.getSaleFinishRatio()).divide(BigDecimal.valueOf(2), 4, BigDecimal.ROUND_DOWN));
        MemberEntity member = memberDao.selectById(mb.getMemberId());
        OtcEntrustOrder query = new OtcEntrustOrder();
        query.setMemberId(mb.getMemberId());
        query.setIsDefualt(1);
        query.setOrderType(OtcEntrustOrder.ORDER_TYPE_B);
        query.setStatus(OtcEntrustOrder.LINE_UP);
        List<OtcEntrustOrder> buysEntity = otcEntrustOrderDao.selectEntrustOrderByOrderType(query);
        List<EntrustListInfoVo> buys = OtcEntrustOrderMapper.INSTANCE.entrustToListInfoVoList(buysEntity);
        query.setOrderType(OtcEntrustOrder.ORDER_TYPE_S);
        List<OtcEntrustOrder> salesEntity = otcEntrustOrderDao.selectEntrustOrderByOrderType(query);
        List<EntrustListInfoVo> sales = OtcEntrustOrderMapper.INSTANCE.entrustToListInfoVoList(salesEntity);
        mbVo.setBuys(buys);
        mbVo.setSales(sales);
        mbVo.setNikename(member.getName());
        return Result.ok(mbVo);
    }
    @Override
    public Result applyConditions() {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        member = memberDao.selectById(member.getId());
//        long memberId = 444L;
//        MemberEntity member = memberDao.selectById(memberId);
        ApplyConditionsVo applyConditionsVo = new ApplyConditionsVo();
        OtcSetting setting = otcSettingDao.selectById(1L);
        applyConditionsVo.setOrderNum(setting.getOrderNum());
        applyConditionsVo.setTotalAmount(setting.getTotalAmount());
        applyConditionsVo.setCompletionRate(setting.getCompletionRate());
        applyConditionsVo.setCancellNum(setting.getCancellNum());
        // 所有已完成订单
        List<OtcOrder> finishOrders = otcOrderDao.selectOrderListForUser(member.getId(), 3);
        if (CollUtil.isEmpty(finishOrders) || setting.getOrderNum() > finishOrders.size()) {
            applyConditionsVo.setOrderNumStatus(2);
        }else{
            applyConditionsVo.setOrderNumStatus(1);
        }
        List<OtcOrder> allOrders = otcOrderDao.selectOrderListForUser(member.getId(), null);
        if (CollUtil.isNotEmpty(allOrders)) {
            BigDecimal finishRatio = BigDecimal.valueOf(finishOrders.size()).divide(BigDecimal.valueOf(allOrders.size()), 4, BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(100));
            if (setting.getCompletionRate().compareTo(finishRatio) > 0) {
                applyConditionsVo.setCompletionRateStatus(2);
            }else{
                applyConditionsVo.setCompletionRateStatus(1);
            }
        }
        BigDecimal totalAmount = otcOrderDao.selectOrderTotalAmount(member.getId());
        totalAmount = totalAmount == null ? BigDecimal.ZERO : totalAmount;
        if (setting.getTotalAmount().compareTo(totalAmount) > 0) {
            applyConditionsVo.setTotalAmountStatus(2);
        }else{
            applyConditionsVo.setTotalAmountStatus(1);
        }
        Integer certifyStatus = member.getCertifyStatus();
        if(MemberEntity.CERTIFY_STATUS_Y == certifyStatus){
            applyConditionsVo.setMemberAuthStatus(1);
        }else{
            applyConditionsVo.setMemberAuthStatus(2);
        }
        return Result.ok(applyConditionsVo);
    }
}
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcMsgServiceImpl.java
New file
@@ -0,0 +1,252 @@
package com.xcong.excoin.modules.otc.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xcong.excoin.common.LoginUserUtils;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.member.dao.MemberDao;
import com.xcong.excoin.modules.member.dao.MemberSettingDao;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.member.entity.MemberSettingEntity;
import com.xcong.excoin.modules.otc.dao.OtcMsgHistoryDao;
import com.xcong.excoin.modules.otc.dao.OtcMsgUserListDao;
import com.xcong.excoin.modules.otc.dao.OtcOrderDao;
import com.xcong.excoin.modules.otc.dto.*;
import com.xcong.excoin.modules.otc.entity.OtcMsgHistoryEntity;
import com.xcong.excoin.modules.otc.entity.OtcMsgUserListEntity;
import com.xcong.excoin.modules.otc.service.OtcMsgService;
import com.xcong.excoin.modules.otc.vo.ChatBoxVo;
import com.xcong.excoin.modules.otc.vo.ChatOrderVo;
import com.xcong.excoin.modules.otc.vo.MsgListVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Service
@RequiredArgsConstructor
public class OtcMsgServiceImpl extends ServiceImpl<OtcMsgUserListDao, OtcMsgUserListEntity> implements OtcMsgService {
    private final OtcMsgUserListDao otcMsgUserListDao;
    private final OtcMsgHistoryDao otcMsgHistoryDao;
    private final OtcOrderDao otcOrderDao;
    private final MemberSettingDao memberSettingDao;
    private final MemberDao memberDao;
    @Override
    public IPage<MsgListVo> getMsgList(MsgListDto msgListDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        Long memberId = member.getId();
//        Long memberId = 444L;
//        MemberEntity member = memberDao.selectById(memberId);
        Page<MsgListVo> page = new Page<>(msgListDto.getPageNum(), msgListDto.getPageSize());
        OtcMsgUserListEntity otcMsgUserListEntity = new OtcMsgUserListEntity();
        otcMsgUserListEntity.setMemberId(memberId);
        otcMsgUserListEntity.setNickname(msgListDto.getNickname());
        IPage<MsgListVo> msgList = otcMsgUserListDao.getMsgList(otcMsgUserListEntity, page);
        List<MsgListVo> records = msgList.getRecords();
        //更新最外层的消息提醒
        boolean flag = true;
        if(CollUtil.isNotEmpty(records)){
            for(MsgListVo msgListVo : records){
                long targetId = msgListVo.getTargetId();
//                MemberEntity memberEntity = memberDao.selectById(targetId);
//                msgListVo.setNickname(memberEntity.getName());
                ChatOrderVo chatOrderVo = new ChatOrderVo();
                List<ChatOrderVo> chatOrderVos = otcOrderDao.selectOneByMemberIdAndTargetId(memberId,targetId);
                if(CollUtil.isNotEmpty(chatOrderVos)){
                    for(ChatOrderVo chatOrderVodone : chatOrderVos){
                        Long memberIdDone = chatOrderVodone.getMemberId();
                        if(memberId.equals(memberIdDone) || memberId == memberIdDone){
                            chatOrderVo = chatOrderVodone;
                        }
                    }
                }
                msgListVo.setChatOrderVo(chatOrderVo);
                Integer isRead = msgListVo.getIsRead();
                if(OtcMsgUserListEntity.ISREAD_ONE == isRead){
                    flag = false;
                }
            }
            if(flag){
                MemberSettingEntity memberSettingEntity = memberSettingDao.selectMemberSettingByMemberId(member.getId());
                memberSettingEntity.setMessageReminder(0);
                memberSettingDao.updateById(memberSettingEntity);
            }
        }
        return msgList;
    }
    @Override
    @Transactional
    public Result getChatBox(ChatBoxDto chatBoxDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
//        MemberEntity member = memberDao.selectById(443L);
        //对话是否存在
        long id = chatBoxDto.getId();
        if(ObjectUtil.isEmpty(id)){
            return Result.fail("请下拉刷新");
        }
        OtcMsgUserListEntity otcMsgUserListEntity = otcMsgUserListDao.selectById(id);
        if(ObjectUtil.isEmpty(otcMsgUserListEntity)){
            return Result.fail("请下拉刷新");
        }
        //更新为已读
        otcMsgUserListEntity.setIsRead(OtcMsgUserListEntity.ISREAD_TWO);
        otcMsgUserListDao.updateById(otcMsgUserListEntity);
        long memberId = otcMsgUserListEntity.getMemberId();
        long targetId = otcMsgUserListEntity.getTargetId();
        Page<ChatBoxVo> page = new Page<>(chatBoxDto.getPageNum(), chatBoxDto.getPageSize());
        OtcMsgHistoryEntity otcMsgHistoryEntity = new OtcMsgHistoryEntity();
        otcMsgHistoryEntity.setMemberId(memberId);
        otcMsgHistoryEntity.setTargetId(targetId);
        IPage<ChatBoxVo> chatBoxVos= otcMsgHistoryDao.getChatBoxMsgList(page,otcMsgHistoryEntity);
        return Result.ok(chatBoxVos);
    }
    @Override
    @Transactional
    public Result sendMsg(SendMsgDto sendMsgDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        Long memberId = member.getId();
//        Long memberId = 449L;
        long targetId = sendMsgDto.getTargetId();
        if(ObjectUtil.isEmpty(targetId)){
            return Result.fail("对话用户不存在");
        }
        MemberEntity memberEntity = memberDao.selectById(targetId);
        if(ObjectUtil.isEmpty(memberEntity)){
            return Result.fail("对话用户不存在");
        }
        String msg = sendMsgDto.getMsg();
        if(StrUtil.isEmpty(msg)){
            return Result.fail("请输入发送消息");
        }
        Integer msgType = sendMsgDto.getMsgType();
        if(ObjectUtil.isEmpty(msgType)){
            return Result.fail("请输入发送消息");
        }
        //发送方
        List<OtcMsgUserListEntity> otcMsgUserListEntityFrom = otcMsgUserListDao.selectListByMemberIdAndTargetId(memberId,targetId);
        if(CollUtil.isEmpty(otcMsgUserListEntityFrom)){
            OtcMsgUserListEntity otcMsgUserListEntity = new OtcMsgUserListEntity();
            otcMsgUserListEntity.setMemberId(memberId);
            otcMsgUserListEntity.setTargetId(targetId);
            otcMsgUserListEntity.setIsRead(OtcMsgUserListEntity.ISREAD_TWO);
            otcMsgUserListEntity.setLastMsgTime(DateUtil.date());
            otcMsgUserListDao.insert(otcMsgUserListEntity);
        }else{
            OtcMsgUserListEntity otcMsgUserListEntity = otcMsgUserListEntityFrom.get(0);
            otcMsgUserListEntity.setMemberId(memberId);
            otcMsgUserListEntity.setTargetId(targetId);
            otcMsgUserListEntity.setIsRead(OtcMsgUserListEntity.ISREAD_TWO);
            otcMsgUserListEntity.setLastMsgTime(DateUtil.date());
            otcMsgUserListDao.updateById(otcMsgUserListEntity);
        }
        //历史消息中增加新纪录
        OtcMsgHistoryEntity otcMsgHistoryEntityFrom = new OtcMsgHistoryEntity();
        otcMsgHistoryEntityFrom.setMemberId(memberId);
        otcMsgHistoryEntityFrom.setFromMemberId(memberId);
        otcMsgHistoryEntityFrom.setTargetId(targetId);
        otcMsgHistoryEntityFrom.setMsg(msg);
        otcMsgHistoryEntityFrom.setMsgType(msgType);
        otcMsgHistoryEntityFrom.setIsSelf(OtcMsgHistoryEntity.ISSELF_ONE);
        otcMsgHistoryDao.insert(otcMsgHistoryEntityFrom);
        //接受方
        List<OtcMsgUserListEntity> otcMsgUserListEntityTo = otcMsgUserListDao.selectListByMemberIdAndTargetId(targetId,memberId);
        if(CollUtil.isEmpty(otcMsgUserListEntityTo)){
            OtcMsgUserListEntity otcMsgUserListEntity = new OtcMsgUserListEntity();
            otcMsgUserListEntity.setMemberId(targetId);
            otcMsgUserListEntity.setTargetId(memberId);
            otcMsgUserListEntity.setIsRead(OtcMsgUserListEntity.ISREAD_ONE);
            otcMsgUserListEntity.setLastMsgTime(DateUtil.date());
            otcMsgUserListDao.insert(otcMsgUserListEntity);
        }else{
            OtcMsgUserListEntity otcMsgUserListEntity = otcMsgUserListEntityTo.get(0);
            otcMsgUserListEntity.setMemberId(targetId);
            otcMsgUserListEntity.setTargetId(memberId);
            otcMsgUserListEntity.setIsRead(OtcMsgUserListEntity.ISREAD_ONE);
            otcMsgUserListEntity.setLastMsgTime(DateUtil.date());
            otcMsgUserListDao.updateById(otcMsgUserListEntity);
        }
        //历史消息中增加新纪录
        OtcMsgHistoryEntity otcMsgHistoryEntityTo = new OtcMsgHistoryEntity();
        otcMsgHistoryEntityTo.setMemberId(targetId);
        otcMsgHistoryEntityTo.setFromMemberId(memberId);
        otcMsgHistoryEntityTo.setTargetId(targetId);
        otcMsgHistoryEntityTo.setMsg(msg);
        otcMsgHistoryEntityTo.setMsgType(msgType);
        otcMsgHistoryEntityTo.setIsSelf(OtcMsgHistoryEntity.ISSELF_TWO);
        otcMsgHistoryDao.insert(otcMsgHistoryEntityTo);
        //增加一个提醒的
        MemberSettingEntity memberSettingEntity = memberSettingDao.selectMemberSettingByMemberId(targetId);
        memberSettingEntity.setMessageReminder(1);
        memberSettingDao.updateById(memberSettingEntity);
        return Result.ok("发送成功");
    }
    @Override
    public Result getChatBoxConnect(ConnectDto connectDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        Long memberId = member.getId();
//        Long memberId = 443L;
        long targetId = connectDto.getTargetId();
        if(ObjectUtil.isEmpty(targetId)){
            return Result.fail("请返回重试");
        }
        IPage<ChatBoxVo> chatBoxVos= new Page<>();
        List<OtcMsgUserListEntity> otcMsgUserListEntitys = otcMsgUserListDao.selectListByMemberIdAndTargetId(memberId,targetId);
        if(CollUtil.isNotEmpty(otcMsgUserListEntitys)){
            Page<ChatBoxVo> page = new Page<>(connectDto.getPageNum(), connectDto.getPageSize());
            OtcMsgHistoryEntity otcMsgHistoryEntity = new OtcMsgHistoryEntity();
            otcMsgHistoryEntity.setMemberId(memberId);
            otcMsgHistoryEntity.setTargetId(targetId);
            chatBoxVos = otcMsgHistoryDao.getChatBoxMsgList(page,otcMsgHistoryEntity);
        }
        return Result.ok(chatBoxVos);
    }
    @Override
    public Result getChatOrder(ChatOrderDto chatOrderDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        Long memberId = member.getId();
//        Long memberId = 443L;
        long targetId = chatOrderDto.getTargetId();
        if(ObjectUtil.isEmpty(targetId)){
            return Result.fail("请返回重试");
        }
        ArrayList<ChatOrderVo> chatOrderVoList = new ArrayList<>();
        List<ChatOrderVo> chatOrderVos = otcOrderDao.selectByMemberIdAndTargetId(memberId,targetId);
        if(CollUtil.isNotEmpty(chatOrderVos)){
            for(ChatOrderVo chatOrderVo : chatOrderVos){
                Long memberIdDone = chatOrderVo.getMemberId();
                if(memberId.equals(memberIdDone) || memberId == memberIdDone){
                    chatOrderVoList.add(chatOrderVo);
                }
            }
        }
        return Result.ok(chatOrderVoList);
    }
}
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcOrderAppealServiceImpl.java
New file
@@ -0,0 +1,13 @@
package com.xcong.excoin.modules.otc.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xcong.excoin.modules.otc.entity.OtcOrderAppeal;
import com.xcong.excoin.modules.otc.dao.OtcOrderAppealDao;
import com.xcong.excoin.modules.otc.service.OtcOrderAppealService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class OtcOrderAppealServiceImpl extends ServiceImpl<OtcOrderAppealDao, OtcOrderAppeal> implements OtcOrderAppealService {
}
src/main/java/com/xcong/excoin/modules/otc/service/impl/OtcOrderServiceImpl.java
New file
@@ -0,0 +1,507 @@
package com.xcong.excoin.modules.otc.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xcong.excoin.common.LoginUserUtils;
import com.xcong.excoin.common.contants.AppContants;
import com.xcong.excoin.common.exception.GlobalException;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.common.system.service.CommonService;
import com.xcong.excoin.modules.member.dao.MemberDao;
import com.xcong.excoin.modules.member.dao.MemberPaymentMethodDao;
import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.member.entity.MemberPaymentMethodEntity;
import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
import com.xcong.excoin.modules.otc.dao.*;
import com.xcong.excoin.modules.otc.dto.HasPayDto;
import com.xcong.excoin.modules.otc.dto.OrderApealDto;
import com.xcong.excoin.modules.otc.dto.OrderListDto;
import com.xcong.excoin.modules.otc.dto.OtcOrderAddDto;
import com.xcong.excoin.modules.otc.entity.*;
import com.xcong.excoin.modules.otc.service.OtcOrderService;
import com.xcong.excoin.modules.otc.vo.BuyOrderDetailVo;
import com.xcong.excoin.modules.otc.vo.OrderListVo;
import com.xcong.excoin.modules.otc.vo.SaleOrderDetailVo;
import com.xcong.excoin.rabbit.producer.OtcProducter;
import com.xcong.excoin.utils.RedisUtils;
import com.xcong.excoin.utils.ThreadPoolUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Slf4j
@Service
@RequiredArgsConstructor
public class OtcOrderServiceImpl extends ServiceImpl<OtcOrderDao, OtcOrder> implements OtcOrderService {
    private final OtcMarketBussinessDao otcMarketBussinessDao;
    private final OtcEntrustOrderDao otcEntrustOrderDao;
    private final OtcOrderAppealDao otcOrderAppealDao;
    private final CommonService commonService;
    private final MemberWalletCoinDao memberWalletCoinDao;
    private final MemberDao memberDao;
    private final MemberPaymentMethodDao memberPaymentMethodDao;
    private final OtcBlackListDao otcBlackListDao;
    private final OtcSettingDao otcSettingDao;
    private final RedisUtils redisUtils;
    private final OtcProducter otcProducter;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result buyOrder(OtcOrderAddDto orderAddDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
//        MemberEntity member = memberDao.selectById(445L);
        OtcEntrustOrder entrustOrder = otcEntrustOrderDao.selectById(orderAddDto.getId());
        if (entrustOrder == null) {
            throw new GlobalException("委托单不存在");
        }
        if (member.getId().equals(entrustOrder.getMemberId())) {
            throw new GlobalException("不能购买自己的委托单");
        }
        if (!OtcEntrustOrder.ORDER_TYPE_S.equals(entrustOrder.getOrderType())) {
            throw new GlobalException("无法购买");
        }
        OtcSetting setting = otcSettingDao.selectById(1L);
        String times = redisUtils.getString(AppContants.OTC_ORDER_CANCEL_TIMES + member.getId());
        times = times == null ? "0" :times;
        if (setting.getCancellNum() <= Integer.parseInt(times)) {
            throw new GlobalException("订单取消次数过多, 限制交易24小时");
        }
        if (orderAddDto.getCnyAmount().compareTo(entrustOrder.getLimitMinAmount()) < 0) {
            throw new GlobalException("低于最低限额");
        }
        if (orderAddDto.getCnyAmount().compareTo(entrustOrder.getLimitMaxAmount()) > 0) {
            throw new GlobalException("高于最高限额");
        }
        if (orderAddDto.getUsdtAmount().compareTo(entrustOrder.getRemainCoinAmount()) > 0) {
            throw new GlobalException("剩余数量不足");
        }
        BigDecimal cny = orderAddDto.getUsdtAmount().multiply(entrustOrder.getUnitPrice()).setScale(2, BigDecimal.ROUND_DOWN);
        BigDecimal usdt = orderAddDto.getCnyAmount().divide(entrustOrder.getUnitPrice(), 2, BigDecimal.ROUND_DOWN);
        if (cny.compareTo(orderAddDto.getCnyAmount()) != 0 && usdt.compareTo(orderAddDto.getUsdtAmount()) != 0) {
            log.info("BUY = CNY:{}, CNY_{}, USDT:{}, USDT_{}", cny, orderAddDto.getCnyAmount(), usdt, orderAddDto.getUsdtAmount());
            throw new GlobalException("数量与金额不符");
        }
        /**
         * 最多三单未付款
         */
        QueryWrapper<OtcOrder> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("member_id",member.getId());
        objectQueryWrapper.lt("status",OtcOrder.STATUS_PAY);
        List<OtcOrder> otcOrders = this.baseMapper.selectList(objectQueryWrapper);
        if(CollUtil.isNotEmpty(otcOrders)){
            if(otcOrders.size() >= 3){
                throw new GlobalException("最多可同时有三个待付款订单");
            }
        }
        OtcOrder otcOrder = new OtcOrder();
        otcOrder.setOrderNo(commonService.generateOrderNo(member.getId()));
        otcOrder.setUnitPrice(entrustOrder.getUnitPrice());
        otcOrder.setEntrustOrderId(entrustOrder.getId());
        otcOrder.setCoinAmount(orderAddDto.getUsdtAmount());
        otcOrder.setTotalAmount(orderAddDto.getCnyAmount());
        otcOrder.setMemberId(member.getId());
        otcOrder.setOppositeMemberId(entrustOrder.getMemberId());
        otcOrder.setStatus(OtcOrder.STATUS_SUBMIT);
        otcOrder.setPayTime(new Date());
        otcOrder.setEntrustMemberId(entrustOrder.getMemberId());
        otcOrder.setOrderType(OtcEntrustOrder.ORDER_TYPE_B);
        MemberPaymentMethodEntity defualtMethod = memberPaymentMethodDao.selectDefualtMethod(entrustOrder.getMemberId(), null, "1");
        if (defualtMethod == null) {
            throw new GlobalException("对方未设置默认支付方式");
        }
        if (MemberPaymentMethodEntity.PAYMENTTYPE_CARD.toString().equals(defualtMethod.getPaymentType())) {
            otcOrder.setBankName(defualtMethod.getBank());
        } else {
            otcOrder.setBankName(defualtMethod.getPaymentQrcode());
        }
        otcOrder.setBankNo(defualtMethod.getAccount());
        otcOrder.setCardName(defualtMethod.getName());
        otcOrder.setPayType(defualtMethod.getPaymentType());
        OtcOrder sale = new OtcOrder();
        BeanUtil.copyProperties(otcOrder, sale);
        sale.setMemberId(entrustOrder.getMemberId());
        sale.setOppositeMemberId(member.getId());
        sale.setOrderType(OtcEntrustOrder.ORDER_TYPE_S);
        otcEntrustOrderDao.updateRemainAmount(entrustOrder.getId(), orderAddDto.getUsdtAmount().negate());
        this.baseMapper.insert(otcOrder);
        this.baseMapper.insert(sale);
        ThreadPoolUtils.sendOrderMsg();
        return Result.ok("购买成功", otcOrder.getId());
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result saleOrder(OtcOrderAddDto orderAddDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcEntrustOrder entrustOrder = otcEntrustOrderDao.selectById(orderAddDto.getId());
        if (entrustOrder == null) {
            throw new GlobalException("委托单不存在");
        }
        if (member.getId().equals(entrustOrder.getMemberId())) {
            throw new GlobalException("不能购买自己的委托单");
        }
        if (!OtcEntrustOrder.ORDER_TYPE_B.equals(entrustOrder.getOrderType())) {
            throw new GlobalException("无法出售");
        }
        OtcSetting setting = otcSettingDao.selectById(1L);
        String times = redisUtils.getString(AppContants.OTC_ORDER_CANCEL_TIMES + member.getId());
        times = times == null ? "0" :times;
        if (setting.getCancellNum() <= Integer.parseInt(times)) {
            throw new GlobalException("订单取消次数过多, 限制交易24小时");
        }
        if (orderAddDto.getCnyAmount().compareTo(entrustOrder.getLimitMinAmount()) < 0) {
            throw new GlobalException("低于最低限额");
        }
        if (orderAddDto.getCnyAmount().compareTo(entrustOrder.getLimitMaxAmount()) > 0) {
            throw new GlobalException("高于最高限额");
        }
        if (orderAddDto.getUsdtAmount().compareTo(entrustOrder.getRemainCoinAmount()) > 0) {
            throw new GlobalException("剩余数量不足");
        }
        if (StrUtil.isBlank(orderAddDto.getPassword())) {
            throw new GlobalException("资金密码不能为空");
        }
        MemberEntity memberEntity = memberDao.selectById(member.getId());
        if (!SecureUtil.md5(orderAddDto.getPassword()).equals(memberEntity.getTradePassword())) {
            throw new GlobalException("资金密码错误");
        }
        BigDecimal cny = orderAddDto.getUsdtAmount().multiply(entrustOrder.getUnitPrice()).setScale(2, BigDecimal.ROUND_DOWN);
        BigDecimal usdt = orderAddDto.getCnyAmount().divide(entrustOrder.getUnitPrice(), 2, BigDecimal.ROUND_DOWN);
        if (cny.compareTo(orderAddDto.getCnyAmount()) != 0 && usdt.compareTo(orderAddDto.getUsdtAmount()) != 0) {
            log.info("SALE = CNY:{}, CNY_{}, USDT:{}, USDT_{}", cny, orderAddDto.getCnyAmount(), usdt, orderAddDto.getUsdtAmount());
            throw new GlobalException("数量与金额不符");
        }
        MemberWalletCoinEntity wallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(member.getId(), "USDT");
        if (wallet.getAvailableBalance().compareTo(orderAddDto.getUsdtAmount()) < 0) {
            throw new GlobalException("钱包余额不足");
        }
        OtcOrder otcOrder = new OtcOrder();
        otcOrder.setOrderNo(commonService.generateOrderNo(member.getId()));
        otcOrder.setUnitPrice(entrustOrder.getUnitPrice());
        otcOrder.setEntrustOrderId(entrustOrder.getId());
        otcOrder.setCoinAmount(orderAddDto.getUsdtAmount());
        otcOrder.setTotalAmount(orderAddDto.getCnyAmount());
        otcOrder.setMemberId(member.getId());
        otcOrder.setStatus(OtcOrder.STATUS_SUBMIT);
        otcOrder.setPayTime(new Date());
        otcOrder.setEntrustMemberId(entrustOrder.getMemberId());
        otcOrder.setOppositeMemberId(entrustOrder.getMemberId());
        otcOrder.setOrderType(OtcEntrustOrder.ORDER_TYPE_S);
        OtcOrder buy = new OtcOrder();
        BeanUtil.copyProperties(otcOrder, buy);
        buy.setMemberId(entrustOrder.getMemberId());
        buy.setOppositeMemberId(member.getId());
        buy.setOrderType(OtcEntrustOrder.ORDER_TYPE_B);
        MemberPaymentMethodEntity defualtMethod = memberPaymentMethodDao.selectDefualtMethod(member.getId(), null, "1");
        if (defualtMethod == null) {
            throw new GlobalException("未设置默认支付方式");
        }
        if (MemberPaymentMethodEntity.PAYMENTTYPE_CARD.toString().equals(defualtMethod.getPaymentType())) {
            buy.setBankName(defualtMethod.getBank());
        } else {
            buy.setBankName(defualtMethod.getPaymentQrcode());
        }
        buy.setBankNo(defualtMethod.getAccount());
        buy.setCardName(defualtMethod.getName());
        buy.setPayType(defualtMethod.getPaymentType());
        otcEntrustOrderDao.updateRemainAmount(entrustOrder.getId(), orderAddDto.getUsdtAmount().negate());
        this.baseMapper.insert(otcOrder);
        this.baseMapper.insert(buy);
        memberWalletCoinDao.updateFrozenBalance(member.getId(), wallet.getId(), orderAddDto.getUsdtAmount());
        ThreadPoolUtils.sendOrderMsg();
        return Result.ok("出售成功", otcOrder.getId());
    }
    @Override
    public IPage<OrderListVo> findOrderListInPage(OrderListDto orderListDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        Page<OrderListVo> page = new Page<>(orderListDto.getPageNum(), orderListDto.getPageSize());
        OtcOrder order = new OtcOrder();
        order.setStatus(orderListDto.getStatus());
        order.setMemberId(member.getId());
        return this.baseMapper.selectOrdderListInPage(order, page);
    }
    @Override
    public void hasPay(HasPayDto hasPayDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcOrder otcOrder = this.baseMapper.selectById(hasPayDto.getId());
        if (otcOrder == null) {
            throw new GlobalException("订单不存在");
        }
        if (!OtcOrder.STATUS_SUBMIT.equals(otcOrder.getStatus())) {
            throw new GlobalException("状态不正确");
        }
        if (!OtcEntrustOrder.ORDER_TYPE_B.equals(otcOrder.getOrderType())) {
            throw new GlobalException("不是购买单");
        }
        if (StrUtil.isBlank(hasPayDto.getName())) {
            MemberPaymentMethodEntity defualtMethod = memberPaymentMethodDao.selectDefualtMethod(member.getId(), null, "1");
            hasPayDto.setName(defualtMethod.getName());
        }
        this.baseMapper.updateOrderStatusByOrderNo(OtcOrder.STATUS_PAY, hasPayDto.getName(), otcOrder.getOrderNo());
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void finishOrder(Long id) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcOrder otcOrder = this.baseMapper.selectById(id);
        if (otcOrder == null) {
            throw new GlobalException("订单不存在");
        }
        if (!OtcOrder.STATUS_PAY.equals(otcOrder.getStatus())) {
            throw new GlobalException("状态不正确");
        }
        if (!OtcEntrustOrder.ORDER_TYPE_S.equals(otcOrder.getOrderType())) {
            throw new GlobalException("不是出售单");
        }
        OtcOrder buyOrder = this.baseMapper.selectOrderByOrderNoAndType(otcOrder.getOrderNo(), OtcEntrustOrder.ORDER_TYPE_B);
        OtcOrder saleOrder = this.baseMapper.selectOrderByOrderNoAndType(otcOrder.getOrderNo(), OtcEntrustOrder.ORDER_TYPE_S);
        MemberWalletCoinEntity buyWallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(buyOrder.getMemberId(), "USDT");
        MemberWalletCoinEntity saleWallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(saleOrder.getMemberId(), "USDT");
        // 购买者钱包可用新增币
        memberWalletCoinDao.updateBlockBalance(buyWallet.getId(), buyOrder.getCoinAmount(), BigDecimal.ZERO, 0);
        // 出售者钱包冻结减少币
        memberWalletCoinDao.reduceFrozenBalance(saleWallet.getId(), buyOrder.getCoinAmount());
        this.baseMapper.updateOrderStatusByOrderNo(OtcOrder.STATUS_FINISH, null, otcOrder.getOrderNo());
        otcProducter.sendMarketBussinessMsg(otcOrder.getEntrustOrderId(), OtcOrder.STATUS_FINISH);
//        otcProducter.sendOrderReturn(buyOrder.getOrderNo());
    }
    @Override
    public Result findBuyOrderDetail(Long id) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        member = memberDao.selectById(member.getId());
        OtcOrder otcOrder = this.baseMapper.selectById(id);
        if (otcOrder == null) {
            return Result.fail("订单不存在");
        }
        OtcOrder buyOrder = this.baseMapper.selectOrderByOrderNoAndType(otcOrder.getOrderNo(), OtcEntrustOrder.ORDER_TYPE_B);
        if (buyOrder == null) {
            return Result.fail("参数错误");
        }
        BuyOrderDetailVo buyDetail = new BuyOrderDetailVo();
        buyDetail.setOrderNo(buyOrder.getOrderNo());
        buyDetail.setUsdtAmount(buyOrder.getCoinAmount());
        buyDetail.setStatus(buyOrder.getStatus());
        buyDetail.setTotalAmount(buyOrder.getTotalAmount());
        buyDetail.setUnitPrice(buyOrder.getUnitPrice());
        buyDetail.setCreateTime(buyOrder.getCreateTime());
        buyDetail.setIsMb(member.getAccountType() == 1 ? 2 : 1);
        buyDetail.setPayName(buyOrder.getPayName());
        buyDetail.setIsOwnEntrust(member.getId().equals(buyOrder.getEntrustMemberId()) ? 1 : 2);
        OtcOrder saleOrder = this.baseMapper.selectOrderByOrderNoAndType(otcOrder.getOrderNo(), OtcEntrustOrder.ORDER_TYPE_S);
        MemberEntity saleMember = memberDao.selectById(saleOrder.getMemberId());
        OtcBlackList otcBlackList = otcBlackListDao.selectByMemberIdAndBlackMemberId(member.getId(), buyOrder.getEntrustMemberId());
        if (otcBlackList != null) {
            buyDetail.setIsBlack(1);
        } else {
            buyDetail.setIsBlack(2);
        }
        buyDetail.setSaleName(saleMember.getName());
        buyDetail.setSaleMemberId(saleMember.getId());
        buyDetail.setMemberId(member.getId());
        buyDetail.setBankName(buyOrder.getBankName());
        buyDetail.setBankNo(buyOrder.getBankNo());
        buyDetail.setCardName(buyOrder.getCardName());
        buyDetail.setPayType(buyOrder.getPayType());
        buyDetail.setPayTime(buyOrder.getPayTime());
        if (!buyOrder.getMemberId().equals(buyOrder.getEntrustMemberId())) {
            OtcMarketBussiness otcMb = otcMarketBussinessDao.selectMarketBussinessByMemberId(buyOrder.getEntrustMemberId());
            buyDetail.setMbId(otcMb.getId());
            buyDetail.setFinishRatio(otcMb.getFinishRatio());
            buyDetail.setOrderCnt(otcMb.getBuyCnt());
        }
        if (OtcOrder.STATUS_SUBMIT.equals(buyOrder.getStatus())) {
            long between = DateUtil.between(new Date(), DateUtil.offsetMinute(buyOrder.getCreateTime(), 30), DateUnit.SECOND, false);
            buyDetail.setTimes(between);
        }
        return Result.ok(buyDetail);
    }
    @Override
    public Result findSaleOrderDetail(Long id) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcOrder otcOrder = this.baseMapper.selectById(id);
        if (otcOrder == null) {
            return Result.fail("订单不存在");
        }
        OtcOrder saleOrder = this.baseMapper.selectOrderByOrderNoAndType(otcOrder.getOrderNo(), OtcEntrustOrder.ORDER_TYPE_S);
        if (saleOrder == null) {
            return Result.fail("参数错误");
        }
        MemberEntity buyMember = memberDao.selectById(saleOrder.getOppositeMemberId());
        SaleOrderDetailVo saleDetail = new SaleOrderDetailVo();
        saleDetail.setOrderNo(saleOrder.getOrderNo());
        saleDetail.setUsdtAmount(saleOrder.getCoinAmount());
        saleDetail.setStatus(saleOrder.getStatus());
        saleDetail.setTotalAmount(saleOrder.getTotalAmount());
        saleDetail.setUnitPrice(saleOrder.getUnitPrice());
        saleDetail.setCreateTime(saleOrder.getCreateTime());
        saleDetail.setIsMb(member.getAccountType() == 1 ? 2 : 1);
        saleDetail.setPayName(saleOrder.getPayName());
        saleDetail.setSaleName(buyMember.getName());
        saleDetail.setSaleMemberId(buyMember.getId());
        saleDetail.setMemberId(member.getId());
        saleDetail.setPayType(saleOrder.getPayType());
        saleDetail.setIsOwnEntrust(member.getId().equals(saleOrder.getEntrustMemberId()) ? 1 : 2);
        OtcBlackList otcBlackList = otcBlackListDao.selectByMemberIdAndBlackMemberId(member.getId(), saleOrder.getEntrustMemberId());
        if (otcBlackList != null) {
            saleDetail.setIsBlack(1);
        } else {
            saleDetail.setIsBlack(2);
        }
        if (!saleOrder.getMemberId().equals(saleOrder.getEntrustMemberId())) {
            OtcMarketBussiness otcMb = otcMarketBussinessDao.selectMarketBussinessByMemberId(saleOrder.getEntrustMemberId());
            saleDetail.setMbId(otcMb.getId());
            saleDetail.setFinishRatio(otcMb.getFinishRatio());
            saleDetail.setOrderCnt(otcMb.getBuyCnt());
        }
        if (OtcOrder.STATUS_SUBMIT.equals(saleOrder.getStatus())) {
            long between = DateUtil.between(new Date(), DateUtil.offsetMinute(saleOrder.getCreateTime(), 30), DateUnit.SECOND, false);
            saleDetail.setTimes(between);
        }
        return Result.ok(saleDetail);
    }
    @Override
    public void cancelOrder(Long id) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        OtcOrder otcOrder = this.baseMapper.selectById(id);
        if (otcOrder == null) {
            throw new GlobalException("订单不存在");
        }
        if (!OtcOrder.STATUS_SUBMIT.equals(otcOrder.getStatus())) {
            throw new GlobalException("不能取消");
        }
        OtcOrder saleOrder = this.baseMapper.selectOrderByOrderNoAndType(otcOrder.getOrderNo(), OtcEntrustOrder.ORDER_TYPE_S);
        if (!saleOrder.getMemberId().equals(saleOrder.getEntrustMemberId())) {
            MemberWalletCoinEntity wallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(saleOrder.getMemberId(), "USDT");
            memberWalletCoinDao.subFrozenBalance(saleOrder.getMemberId(), wallet.getId(), saleOrder.getCoinAmount());
        }
        OtcSetting setting = otcSettingDao.selectById(1L);
        String times = redisUtils.getString(AppContants.OTC_ORDER_CANCEL_TIMES + member.getId());
        if (StrUtil.isNotBlank(times)) {
            int i = Integer.parseInt(times);
            i++;
            if (i >= setting.getCancellNum()) {
                redisUtils.set(AppContants.OTC_ORDER_CANCEL_TIMES + member.getId(), i, 86400);
            } else {
                redisUtils.set(AppContants.OTC_ORDER_CANCEL_TIMES + member.getId(), i);
            }
        } else {
            redisUtils.set(AppContants.OTC_ORDER_CANCEL_TIMES + member.getId(), 1, 86400);
        }
        otcEntrustOrderDao.updateRemainAmount(otcOrder.getEntrustOrderId(), otcOrder.getCoinAmount());
        this.baseMapper.updateOrderStatusByOrderNo(OtcOrder.STATUS_CANCEL, null, otcOrder.getOrderNo());
        otcProducter.sendMarketBussinessMsg(otcOrder.getEntrustOrderId(), OtcOrder.STATUS_CANCEL);
    }
    @Override
    public Result orderApeal(OrderApealDto orderApealDto) {
        MemberEntity member = LoginUserUtils.getAppLoginUser();
        Long memberId = member.getId();
//        long memberId = 446L;
        Long orderId = orderApealDto.getOrderId();
        OtcOrder otcOrder = this.baseMapper.selectById(orderId);
        if(ObjectUtil.isEmpty(otcOrder)){
            return Result.fail("订单不存在");
        }
        String reason = orderApealDto.getReason();
        if(StrUtil.isEmpty(reason)){
            return Result.fail("请填写申诉原因");
        }
        List<String> content = orderApealDto.getContent();
        OtcOrderAppeal otcOrderAppeal = new OtcOrderAppeal();
        otcOrderAppeal.setMemberId(memberId);
        otcOrderAppeal.setOrderId(orderId);
        otcOrderAppeal.setReason(reason);
        otcOrderAppeal.setContent(content.toString());
        otcOrderAppeal.setStatus(OtcOrderAppeal.STATUS_ONE);
        otcOrderAppealDao.insert(otcOrderAppeal);
        return Result.ok("成功");
    }
}
src/main/java/com/xcong/excoin/modules/otc/vo/ApplyConditionsVo.java
New file
@@ -0,0 +1,37 @@
package com.xcong.excoin.modules.otc.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@ApiModel(value = "ApplyConditionsVo", description = "接口返回类")
public class ApplyConditionsVo {
    @ApiModelProperty(value = "商家入驻总单数1:满足 2:不满足")
    private Integer orderNumStatus;
    @ApiModelProperty(value = "商家入驻完成率1:满足 2:不满足")
    private Integer completionRateStatus;
    @ApiModelProperty(value = "商家入驻总金额1:满足 2:不满足")
    private Integer totalAmountStatus;
    @ApiModelProperty(value = "实名认证1:满足 2:不满足")
    private Integer memberAuthStatus;
    @ApiModelProperty(value = "总单数")
    private Integer orderNum;
    @ApiModelProperty(value = "完成率")
    private BigDecimal completionRate;
    @ApiModelProperty(value = "总金额")
    private BigDecimal totalAmount;
    @ApiModelProperty(value = "今日取消次数")
    private Integer cancellNum;
}
src/main/java/com/xcong/excoin/modules/otc/vo/BlackListVo.java
New file
@@ -0,0 +1,24 @@
package com.xcong.excoin.modules.otc.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
@ApiModel(value = "BlackListVo", description = "黑名单列表接口返回类")
public class BlackListVo {
    @ApiModelProperty(value = "id")
    private Long id;
    @ApiModelProperty(value = "昵称")
    private String name;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "拉黑时间")
    private Date time;
}
src/main/java/com/xcong/excoin/modules/otc/vo/BuyOrderDetailVo.java
New file
@@ -0,0 +1,82 @@
package com.xcong.excoin.modules.otc.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(value = "OtcOrderDetailVo", description = "otc订单详情")
public class BuyOrderDetailVo {
    @ApiModelProperty(value = "交易总额")
    private BigDecimal totalAmount;
    @ApiModelProperty(value = "交易数量")
    private BigDecimal usdtAmount;
    @ApiModelProperty(value = "单价")
    private BigDecimal unitPrice;
    @ApiModelProperty(value = "订单编号")
    private String orderNo;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty("下单时间")
    private Date createTime;
    @ApiModelProperty(value = "银行名称")
    private String bankName;
    @ApiModelProperty(value = "银行卡号")
    private String bankNo;
    @ApiModelProperty(value = "银行卡姓名")
    private String cardName;
    @ApiModelProperty(value = "支付方式 1-微信 2-支付宝 3-银行卡")
    private String payType;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "支付时间")
    private Date payTime;
    @ApiModelProperty(value = "姓名")
    private String payName;
    @ApiModelProperty(value = "商家昵称")
    private String saleName;
    @ApiModelProperty(value = "商家MemberId")
    private Long saleMemberId;
    @ApiModelProperty(value = "memberId")
    private Long memberId;
    @ApiModelProperty(value = "商家ID")
    private Long mbId;
    @ApiModelProperty(value = "订单数量")
    private Integer orderCnt;
    @ApiModelProperty(value = "完成率")
    private BigDecimal finishRatio;
    @ApiModelProperty(value = "是否市商 1是 2否")
    private Integer isMb;
    @ApiModelProperty(value = "订单状态 1-已提交 2-已付款 3-完成")
    private Integer status;
    @ApiModelProperty(value = "剩余秒数")
    private Long times;
    @ApiModelProperty(value = "是否已拉黑 1-是 2-否")
    private Integer isBlack;
    @ApiModelProperty(value = "是否自己的委托单 1-是 2-否")
    private Integer isOwnEntrust;
}
src/main/java/com/xcong/excoin/modules/otc/vo/ChatBoxVo.java
New file
@@ -0,0 +1,38 @@
package com.xcong.excoin.modules.otc.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
@ApiModel(value = "ChatBoxVo", description = "返回参数类")
public class ChatBoxVo {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "时间")
    private Date createTime;
    @ApiModelProperty(value = "接受ID")
    private long targetId;
    @ApiModelProperty(value = "发送ID")
    private long fromMemberId;
    @ApiModelProperty(value = "用户ID")
    private long memberId;
    //消息
    @ApiModelProperty(value = "消息")
    private String msg;
    //消息类型 1-文本2-图片
    @ApiModelProperty(value = "消息类型 1-文本2-图片")
    private Integer msgType;
    @ApiModelProperty(value = "是否是自己 1:是 2:否")
    private Integer isSelf;
}
src/main/java/com/xcong/excoin/modules/otc/vo/ChatOrderVo.java
New file
@@ -0,0 +1,62 @@
package com.xcong.excoin.modules.otc.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(value = "ChatOrderVo", description = "返回参数类")
public class ChatOrderVo {
    /**
     * 订单编号
     */
    @ApiModelProperty(value = "订单编号")
    private String orderNo;
    private Long memberId;
    /**
     * 单价
     */
    @ApiModelProperty(value = "单价")
    private BigDecimal unitPrice;
    /**
     * 数量
     */
    @ApiModelProperty(value = "数量")
    private BigDecimal usdtAmount;
    /**
     * 总额
     */
    @ApiModelProperty(value = "总额")
    private BigDecimal totalAmount;
    /**
     * 订单状态 1-已提交未付款2-已付款3-已完成
     */
    @ApiModelProperty(value = "订单状态 1-已提交未付款2-已付款3-已完成4-已取消")
    private Integer status;
    public static final Integer STATUS_SUBMIT = 1;
    public static final Integer STATUS_PAY = 2;
    public static final Integer STATUS_FINISH = 3;
    public static final Integer STATUS_CANCEL = 4;
    /**
     * 订单类型 B-买 S-卖
     */
    @ApiModelProperty(value = "订单类型 B-买 S-卖")
    private String orderType;
}
src/main/java/com/xcong/excoin/modules/otc/vo/EntrustListInfoVo.java
New file
@@ -0,0 +1,66 @@
package com.xcong.excoin.modules.otc.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(value = "EntrustListInfoVo", description = "委托单列表返回参数类")
public class EntrustListInfoVo {
    @ApiModelProperty(value= "委托单ID")
    private Long id;
    @ApiModelProperty(value = "单价")
    private BigDecimal unitPrice;
    @ApiModelProperty(value = "限额 最小值")
    private BigDecimal min;
    @ApiModelProperty(value = "限额 最大值")
    private BigDecimal max;
    @ApiModelProperty(value = "数量")
    private BigDecimal amount;
    @ApiModelProperty(value = "剩余数量")
    private BigDecimal remainAmount;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "创建时间")
    private Date createTime;
    @ApiModelProperty(value = "上/下线 1-上线 2-下线")
    private Integer status;
    @ApiModelProperty(value = "订单类型 B/购买 S/出售")
    private String orderType;
    @ApiModelProperty(value = "类型 1-支付宝2-微信3-银行卡")
    private String payType;
    public BigDecimal getUnitPrice() {
        return unitPrice.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getMin() {
        return min.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getMax() {
        return max.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getAmount() {
        return amount.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getRemainAmount() {
        return remainAmount.setScale(2, BigDecimal.ROUND_DOWN);
    }
}
src/main/java/com/xcong/excoin/modules/otc/vo/EntrustListVo.java
New file
@@ -0,0 +1,63 @@
package com.xcong.excoin.modules.otc.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@ApiModel(value = "EntrustListVo", description = "委托单列表接口返回参数类")
public class EntrustListVo {
    @ApiModelProperty(value = "订单ID")
    private Long id;
    @ApiModelProperty(value = "市商ID")
    private Long mbId;
    @ApiModelProperty(value = "单价")
    private BigDecimal unitPrice;
    @ApiModelProperty(value = "市商昵称")
    private String nickname;
    @ApiModelProperty(value = "数量")
    private BigDecimal amount;
    @ApiModelProperty(value = "限额 最小值")
    private BigDecimal min;
    @ApiModelProperty(value = "限额 最大值")
    private BigDecimal max;
    @ApiModelProperty(value = "订单数量")
    private Integer orderCnt;
    @ApiModelProperty(value = "完成率")
    private BigDecimal finishRatio;
    @ApiModelProperty(value = "支付方式 1-支付宝 2-微信 3-银行卡")
    private String payType;
    public BigDecimal getUnitPrice() {
        return unitPrice.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getAmount() {
        return amount.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getMin() {
        return min.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getMax() {
        return max.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getFinishRatio() {
        return finishRatio.multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_DOWN);
    }
}
src/main/java/com/xcong/excoin/modules/otc/vo/EntrustOrderDetailVo.java
New file
@@ -0,0 +1,82 @@
package com.xcong.excoin.modules.otc.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(value = "EntrustOrderDetailVo", description = "获取委托单详情接口返回参数类")
public class EntrustOrderDetailVo {
    @ApiModelProperty(value = "委托单号")
    private String orderNo;
    @ApiModelProperty(value = "单价")
    private BigDecimal unitPrice;
    @ApiModelProperty(value = "委托数量")
    private BigDecimal amount;
    @ApiModelProperty(value = "剩余数量")
    private BigDecimal remainAmount;
    @ApiModelProperty(value = "委托金额")
    private BigDecimal totalAmount;
    @ApiModelProperty(value = "限额 下限")
    private BigDecimal min;
    @ApiModelProperty(value = "限额 上限")
    private BigDecimal max;
    @ApiModelProperty(value = "类型 B-购买 S-出售")
    private String orderType;
    @ApiModelProperty(value = "上/下线 1-上线 2-下线")
    private Integer status;
    @ApiModelProperty(value = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;
    @ApiModelProperty(value = "商家昵称")
    private String name;
    @ApiModelProperty(value = "订单数量")
    private Integer orderCnt;
    @ApiModelProperty(value = "完成率")
    private BigDecimal finishRatio;
    @ApiModelProperty(value = "支付方式")
    private String payType;
    public BigDecimal getUnitPrice() {
        return unitPrice.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getAmount() {
        return amount.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getRemainAmount() {
        return remainAmount.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getTotalAmount() {
        return totalAmount.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getMin() {
        return min.setScale(2, BigDecimal.ROUND_DOWN);
    }
    public BigDecimal getMax() {
        return max.setScale(2, BigDecimal.ROUND_DOWN);
    }
}
src/main/java/com/xcong/excoin/modules/otc/vo/MarketBussinessInfoVo.java
New file
@@ -0,0 +1,51 @@
package com.xcong.excoin.modules.otc.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@ApiModel(value = "MarketBussinessInfoVo", description = "获取市商信息接口返回参数类")
public class MarketBussinessInfoVo {
    @ApiModelProperty(value = "id")
    private Long id;
    @ApiModelProperty(value = "会员ID")
    private Long memberId;
    @ApiModelProperty(value = "昵称")
    private String nikename;
    @ApiModelProperty(value = "审核状态", example = "1-待审核2-审核通过3-审核拒绝")
    private Integer status;
    @ApiModelProperty(value = "服务人数")
    private Integer buyCnt;
    @ApiModelProperty(value = "总单数")
    private Integer totalOrderCnt;
    @ApiModelProperty(value = "完成率")
    private BigDecimal finishRatio;
    @ApiModelProperty(value = "平均付款时间")
    private Integer avgPayTime;
    @ApiModelProperty(value = "平均放币时间")
    private Integer avgCoinTime;
    @ApiModelProperty(value = "卖单")
    private List<EntrustListInfoVo> sales;
    @ApiModelProperty(value = "买单")
    private List<EntrustListInfoVo> buys;
    public BigDecimal getFinishRatio() {
        return finishRatio.multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_DOWN);
    }
}
src/main/java/com/xcong/excoin/modules/otc/vo/MsgListVo.java
New file
@@ -0,0 +1,39 @@
package com.xcong.excoin.modules.otc.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Date;
@Data
@ApiModel(value = "MsgListVo", description = "返回参数类")
public class MsgListVo {
    //用户ID
    @ApiModelProperty(value = "用户ID")
    private long id;
    @ApiModelProperty(value = "昵称")
    private String nickname;
    @ApiModelProperty(value = "对方用户ID")
    private long targetId;
    @ApiModelProperty(value = "用户ID")
    private long memberId;
    //是否已读 1:未读 2:已读
    @ApiModelProperty(value = "是否已读 1:未读 2:已读")
    private Integer isRead;
    //最后聊天时间
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "最后聊天时间")
    private Date lastMsgTime;
    @ApiModelProperty(value = "最新的订单")
    private ChatOrderVo chatOrderVo;
}
src/main/java/com/xcong/excoin/modules/otc/vo/OrderListVo.java
New file
@@ -0,0 +1,43 @@
package com.xcong.excoin.modules.otc.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(value = "OtcOrderListVo", description = "订单列表返回参数类")
public class OrderListVo {
    @ApiModelProperty(value = "订单ID")
    private Long id;
    @ApiModelProperty(value = "订单编号")
    private String orderNo;
    @ApiModelProperty(value = "单价")
    private BigDecimal unitPrice;
    @ApiModelProperty(value = "usdt数量")
    private BigDecimal amount;
    @ApiModelProperty(value = "总金额")
    private BigDecimal totalAmount;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "时间")
    private Date createTime;
    @ApiModelProperty(value = "状态 1-已提交 2-已付款 3-已完成 4-已取消")
    private Integer status;
    @ApiModelProperty(value = "订单类型 B-买/S-卖")
    private String orderType;
    @ApiModelProperty(value = "姓名")
    private String name;
}
src/main/java/com/xcong/excoin/modules/otc/vo/SaleOrderDetailVo.java
New file
@@ -0,0 +1,73 @@
package com.xcong.excoin.modules.otc.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel(value = "OtcOrderDetailVo", description = "otc订单详情")
public class SaleOrderDetailVo {
    @ApiModelProperty(value = "交易总额")
    private BigDecimal totalAmount;
    @ApiModelProperty(value = "交易数量")
    private BigDecimal usdtAmount;
    @ApiModelProperty(value = "单价")
    private BigDecimal unitPrice;
    @ApiModelProperty(value = "订单编号")
    private String orderNo;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty("下单时间")
    private Date createTime;
    @ApiModelProperty(value = "订单状态 1-已提交 2-已付款 3-完成")
    private Integer status;
    @ApiModelProperty(value = "姓名")
    private String payName;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @ApiModelProperty(value = "支付时间")
    private Date payTime;
    @ApiModelProperty(value = "支付方式")
    private String payType;
    @ApiModelProperty(value = "商家昵称")
    private String saleName;
    @ApiModelProperty(value = "商家MemberId")
    private Long saleMemberId;
    @ApiModelProperty(value = "memberId")
    private Long memberId;
    @ApiModelProperty(value = "商家ID")
    private Long mbId;
    @ApiModelProperty(value = "订单数量")
    private Integer orderCnt;
    @ApiModelProperty(value = "完成率")
    private BigDecimal finishRatio;
    @ApiModelProperty(value = "是否市商 1是 2否")
    private Integer isMb;
    @ApiModelProperty(value = "剩余秒数")
    private Long times;
    @ApiModelProperty(value = "是否已拉黑")
    private Integer isBlack;
    @ApiModelProperty(value = "是否自己的委托单 1-是 2-否")
    private Integer isOwnEntrust;
}
src/main/java/com/xcong/excoin/modules/otc/vo/TeamVo.java
New file
@@ -0,0 +1,28 @@
package com.xcong.excoin.modules.otc.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@ApiModel(value = "TeamVo", description = "我的团队接口返回参数类")
public class TeamVo {
    @ApiModelProperty(value = "邀请码")
    private String inviteId;
    @ApiModelProperty(value = "级别")
    private int level;
    @ApiModelProperty(value = "金额")
    private BigDecimal amount;
    @ApiModelProperty(value = "团队人数")
    private Integer cnt;
    public BigDecimal getAmount() {
        return amount == null ? BigDecimal.ZERO : amount.setScale(4, BigDecimal.ROUND_DOWN);
    }
}
src/main/java/com/xcong/excoin/netty/bean/AuthRequest.java
New file
@@ -0,0 +1,29 @@
package com.xcong.excoin.netty.bean;
import java.io.Serializable;
public class AuthRequest implements Serializable {
    private static final long serialVersionUID = 5557983797622950620L;
    private Integer cmd;
    private String token;
    public Integer getCmd() {
        return cmd;
    }
    public void setCmd(Integer cmd) {
        this.cmd = cmd;
    }
    public String getToken() {
        return token;
    }
    public void setToken(String token) {
        this.token = token;
    }
}
src/main/java/com/xcong/excoin/netty/bean/ChatRequest.java
New file
@@ -0,0 +1,31 @@
package com.xcong.excoin.netty.bean;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 *  {"data": {"fromMemberId": 443, "isSelf": 1, "memberId": 443, "msg": "w shi shei ", "msgType": 1, "targetId": 444}, "type": 2}
 */
@Data
public class ChatRequest implements Serializable {
    private static final long serialVersionUID = 3079080008111369136L;
    private Long fromMemberId;
    private Long targetId;
    private Long memberId;
    private Integer msgType;
    private String msg;
    private Integer isSelf;
    private Integer cmd;
    private Long timestamp;
}
src/main/java/com/xcong/excoin/netty/bean/RequestBean.java
@@ -3,47 +3,19 @@
import java.io.Serializable;
/**
 * @author wzy
 * @email wangdoubleone@gmail.com
 * @date 2019-05-09
 */
public class RequestBean implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 请求类型
     * 请求类型 1-鉴权 2-发送消息
     */
    private String type;
    private Integer type;
    /**
     * 当前通道id
     */
    private Object data;
    private String channelId;
    /**
     * web端通道ID
     */
    private String reqId;
    /**
     * 请求参数
     */
    private String params;
    /**
     * 手持端是否同意连接 0-否 1-是
     */
    private String tag;
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getChannelId() {
        return channelId;
@@ -53,38 +25,19 @@
        this.channelId = channelId;
    }
    public String getParams() {
        return params;
    public Object getData() {
        return data;
    }
    public void setParams(String params) {
        this.params = params;
    public void setData(Object data) {
        this.data = data;
    }
    public String getReqId() {
        return reqId;
    public Integer getType() {
        return type;
    }
    public void setReqId(String reqId) {
        this.reqId = reqId;
    }
    public String getTag() {
        return tag;
    }
    public void setTag(String tag) {
        this.tag = tag;
    }
    @Override
    public String toString() {
        return "RequestBean{" +
                "type='" + type + '\'' +
                ", channelId='" + channelId + '\'' +
                ", reqId='" + reqId + '\'' +
                ", params='" + params + '\'' +
                ", tag='" + tag + '\'' +
                '}';
    public void setType(Integer type) {
        this.type = type;
    }
}
src/main/java/com/xcong/excoin/netty/bean/ResponseBean.java
@@ -5,85 +5,54 @@
import java.util.List;
import java.util.Map;
/**
 * @author wzy
 * @date 2020-04-18 16:17
 **/
public class ResponseBean implements Serializable {
    private static final long serialVersionUID = 1L;
    public static final String SUCCESS = "200";
    /**
     *  1-鉴权 2-发送消息 3-新消息提醒
     */
    private Integer type;
    private String status;
    private Integer status;
    private String type;
    private Object data;
    private String info;
    private String channelId;
    private Map<Object, Object> mapInfo = new HashMap<>();
    private List<?> row;
    public static ResponseBean ok(String type, String info) {
        ResponseBean responseBean = new ResponseBean();
        responseBean.status = SUCCESS;
        responseBean.type = type;
        responseBean.info = info;
        return responseBean;
    }
    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }
    public String getType() {
    public Integer getType() {
        return type;
    }
    public void setType(String type) {
    public void setType(Integer type) {
        this.type = type;
    }
    public String getInfo() {
        return info;
    public Integer getStatus() {
        return status;
    }
    public void setInfo(String info) {
        this.info = info;
    public void setStatus(Integer status) {
        this.status = status;
    }
    public String getChannelId() {
        return channelId;
    public Object getData() {
        return data;
    }
    public void setChannelId(String channelId) {
        this.channelId = channelId;
    public void setData(Object data) {
        this.data = data;
    }
    public Map<Object, Object> getMapInfo() {
        return mapInfo;
    public static ResponseBean fail(){
        ResponseBean res = new ResponseBean();
        res.setStatus(0);
        return res;
    }
    public void setMapInfo(Map<Object, Object> mapInfo) {
        this.mapInfo = mapInfo;
    }
    public void putInfo(Object key, Object value) {
        this.mapInfo.put(key, value);
    }
    public List<?> getRow() {
        return row;
    }
    public void setRow(List<?> row) {
        this.row = row;
    public static ResponseBean ok(Object data) {
        ResponseBean res = new ResponseBean();
        res.setStatus(1);
        res.setData(data);
        return res;
    }
}
src/main/java/com/xcong/excoin/netty/common/ChannelManager.java
@@ -23,9 +23,20 @@
    // 当前连接到服务器的通道(tcp和websocket)
    private static final ConcurrentMap<String, ChannelId> CHANNEL_MAP = new ConcurrentHashMap<>();
    // key - 用户ID value - 通道ID
    private static final ConcurrentMap<String, ChannelId> MEMBER_CHANNEL = new ConcurrentHashMap<>();
    // key - 通道 value - 用户
    private static final ConcurrentMap<ChannelId, String> CHANNEL_MEMBER = new ConcurrentHashMap<>();
    public static void addWebSocketChannel(Channel channel) {
        WEBSOCKET_GROUP.add(channel);
        CHANNEL_MAP.put(channel.id().asShortText(), channel.id());
    }
    public static void addWsChannel(Channel channel, Long memberId) {
        MEMBER_CHANNEL.put(memberId.toString(), channel.id());
        CHANNEL_MEMBER.put(channel.id(), memberId.toString());
    }
    public static void removeWebSocketChannel(Channel channel) {
@@ -33,9 +44,27 @@
        CHANNEL_MAP.remove(channel.id().asShortText());
    }
    public static void removeWsChannel(Channel channel, Long memberId) {
        MEMBER_CHANNEL.remove(memberId.toString());
        CHANNEL_MEMBER.remove(channel.id());
    }
    public static Channel findWebSocketChannel(String id){
        ChannelId channelId = CHANNEL_MAP.get(id);
        return WEBSOCKET_GROUP.find(channelId);
    }
    public static Channel findWsChannel(Long id){
        ChannelId channelId = MEMBER_CHANNEL.get(id.toString());
        if (channelId == null) {
            return null;
        }
        return WEBSOCKET_GROUP.find(channelId);
    }
    public static String findWsMemberId(Channel channel) {
        return CHANNEL_MEMBER.get(channel.id());
    }
    public static ChannelGroup getWebSocketGroup() {
@@ -46,10 +75,10 @@
        if (WEBSOCKET_GROUP.size() == 0) {
            return;
        }
        ResponseBean responseBean = ResponseBean.ok(type, null);
        responseBean.putInfo("data", object);
        String msg = JSONObject.toJSONString(responseBean);
        WEBSOCKET_GROUP.writeAndFlush(NettyTools.webSocketBytes(msg));
//        ResponseBean responseBean = ResponseBean.ok(type, null);
//        responseBean.putInfo("data", object);
//        String msg = JSONObject.toJSONString(responseBean);
//        WEBSOCKET_GROUP.writeAndFlush(NettyTools.webSocketBytes(msg));
    }
src/main/java/com/xcong/excoin/netty/common/Contans.java
@@ -8,16 +8,8 @@
    public static final String HEART_BEAT = "ping pong pang";
    public static final String WEB_REQ_CONNECTION = "000_000";
    public static final int AUTH_CHECK = 1;
    public static final String HOME_SYMBOLS = "001_001";
    public static final String ORDER_COIN_PRE_ORDER_DATA = "002_001";
    public static final String ORDER_COIN_FIND_TRUST_ORDER = "002_002";
    public static final String ORDER_PRE_ORDER_DATA = "003_001";
    public static final String ORDER_FIND_TRUST_ORDER = "003_002";
    public static final int MESSAGE = 2;
}
src/main/java/com/xcong/excoin/netty/common/NettyTools.java
@@ -1,5 +1,7 @@
package com.xcong.excoin.netty.common;
import com.alibaba.fastjson.JSONObject;
import com.xcong.excoin.netty.bean.ResponseBean;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
@@ -21,7 +23,16 @@
        return Unpooled.copiedBuffer((msg + "_split").getBytes());
    }
    public static TextWebSocketFrame wsSendMsg(ResponseBean responseBean) {
        String res = JSONObject.toJSONString(responseBean);
        return new TextWebSocketFrame(res);
    }
    public static TextWebSocketFrame webSocketBytes(String msg) {
        return new TextWebSocketFrame(msg);
    }
    public static TextWebSocketFrame webSocketJson(Object object) {
        return webSocketBytes(JSONObject.toJSONString(object));
    }
}
src/main/java/com/xcong/excoin/netty/dispatch/MsgDispatch.java
@@ -1,9 +1,14 @@
package com.xcong.excoin.netty.dispatch;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.xcong.excoin.netty.bean.RequestBean;
import com.xcong.excoin.netty.bean.ResponseBean;
import com.xcong.excoin.netty.common.ChannelManager;
import com.xcong.excoin.netty.common.Contans;
import com.xcong.excoin.netty.common.NettyTools;
import com.xcong.excoin.netty.logic.MsgLogic;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
@@ -19,28 +24,28 @@
 */
@Slf4j
@Component("msgDispatch")
public class MsgDispatch implements ApplicationContextAware {
    private ApplicationContext applicationContext;
public class MsgDispatch {
    @Autowired
    private MsgLogic msgLogic;
    public void webSocketDispatch(ChannelHandlerContext ctx, String msg) {
        RequestBean requestBean = null;
        RequestBean requestBean = JSONObject.parseObject(msg, RequestBean.class);
        // 判断当前通道用户是否已经登陆
        if (StrUtil.isEmpty(ChannelManager.findWsMemberId(ctx.channel())) && requestBean.getType() != Contans.AUTH_CHECK) {
            ResponseBean res = ResponseBean.fail();
            res.setType(requestBean.getType());
            ctx.channel().writeAndFlush(NettyTools.webSocketBytes(JSONObject.toJSONString(res)));
            return;
        }
        try {
            requestBean = JSONObject.parseObject(msg, RequestBean.class);
            requestBean.setChannelId(ctx.channel().id().asShortText());
            msgLogic.webSocketMsgLogic(requestBean);
        } catch (Exception e) {
            log.info("#websocket json error:{}#", e);
            ctx.channel().writeAndFlush(NettyTools.webSocketBytes("params error"));
            log.info("#websocket json error:#", e);
            ctx.channel().writeAndFlush(NettyTools.wsSendMsg(ResponseBean.fail()));
        }
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
src/main/java/com/xcong/excoin/netty/handler/WebSocketServerHandler.java
@@ -5,6 +5,7 @@
import com.xcong.excoin.netty.common.Contans;
import com.xcong.excoin.netty.common.NettyTools;
import com.xcong.excoin.netty.dispatch.MsgDispatch;
import com.xcong.excoin.utils.SpringContextHolder;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
@@ -29,9 +30,11 @@
import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
/**
 * @author wzy
 * @email wangdoubleone@gmail.com
 * @date 2019-05-06
 * 项目启动时,在控制台有
 * Unable to proxy interface-implementing method [public final void io.netty.channel.ChannelInitializer.channelRegistered(io.netty.channel.ChannelHandlerContext) throws java.lang.Exception] because it is marked as final: Consider using interface-based JDK proxies instead!
 * 输出
 * 表明,此类将走代理enhancerbyspringcglib代理
 * 此时,获取到此类将为null(不知道原因),从而导致netty连接在初始化时会有空指针异常
 */
@Slf4j
@Component
@@ -44,8 +47,8 @@
    private WebSocketServerHandshaker handshaker;
    @Resource(name = "msgDispatch")
    private MsgDispatch msgDispatch;
//    @Resource(name = "msgDispatch")
//    private MsgDispatch msgDispatch;
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
@@ -75,8 +78,9 @@
                content = ((TextWebSocketFrame) frame).text();
                if (content.contains(Contans.HEART_BEAT)) {
                    resetTimes(ctx.channel());
//                    ctx.channel().writeAndFlush(NettyTools.webSocketBytes(Contans.HEART_BEAT));
                } else {
                    this.msgDispatch.webSocketDispatch(ctx, content);
                    SpringContextHolder.getBean(MsgDispatch.class).webSocketDispatch(ctx, content);
                }
            } catch (ClassCastException e) {
                content = ((CloseWebSocketFrame) frame).reasonText();
@@ -87,12 +91,27 @@
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        log.info("[触发器触发]");
//        super.userEventTriggered(ctx, evt);
//        log.info("[触发器触发]");
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                Integer times = pingTimes.get(ctx.channel().id().asShortText());
                if (times == null) {
                    times = 0;
                }
                /*读超时*/
//                log.info("===服务端===({}读超时, {})", ctx.channel().id().asShortText(), times);
                // 失败计数器次数大于等于3次的时候,关闭链接,等待client重连
                if (times >= MAX_UN_REC_PING_TIMES) {
                    log.info("===服务端===(读超时,关闭chanel)");
                    // 连续超过N次未收到client的ping消息,那么关闭该通道,等待client重连
                    ctx.channel().close();
                } else {
                    // 失败计数器加1
                    times++;
                    pingTimes.remove(ctx.channel().id().asShortText());
                    pingTimes.put(ctx.channel().id().asShortText(), times);
                }
            } else if (event.state() == IdleState.WRITER_IDLE) {
                /*写超时*/
                ctx.channel().writeAndFlush(NettyTools.webSocketBytes(Contans.HEART_BEAT));
src/main/java/com/xcong/excoin/netty/initalizer/WebSocketServerInitializer.java
@@ -19,9 +19,6 @@
@Component
public class WebSocketServerInitializer extends ChannelInitializer<NioSocketChannel> {
    @Autowired
    private WebSocketServerHandler webSocketServerHandler;
    @Override
    protected void initChannel(NioSocketChannel ch) throws Exception {
        ChannelPipeline cp = ch.pipeline();
@@ -32,8 +29,8 @@
        cp.addLast(new HttpObjectAggregator(65536));
        cp.addLast(new ChunkedWriteHandler());
        // 心跳
        ch.pipeline().addLast(new IdleStateHandler(0, 10, 0));
        ch.pipeline().addLast(new IdleStateHandler(10, 0, 0));
        // 自定义业务handler
        cp.addLast(webSocketServerHandler);
        cp.addLast(new WebSocketServerHandler());
    }
}
src/main/java/com/xcong/excoin/netty/logic/WebSocketLogic.java
@@ -1,11 +1,22 @@
package com.xcong.excoin.netty.logic;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.fastjson.JSONObject;
import com.xcong.excoin.common.contants.AppContants;
import com.xcong.excoin.configurations.properties.SecurityProperties;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.netty.bean.ChatRequest;
import com.xcong.excoin.netty.bean.RequestBean;
import com.xcong.excoin.netty.bean.ResponseBean;
import com.xcong.excoin.netty.common.ChannelManager;
import com.xcong.excoin.netty.common.NettyTools;
import com.xcong.excoin.rabbit.producer.ChatProducer;
import com.xcong.excoin.utils.RedisUtils;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -14,28 +25,76 @@
 * @email wangdoubleone@gmail.com
 * @date 2019-05-09
 */
@Slf4j
@Component
public class WebSocketLogic {
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private ChatProducer chatProducer;
    @Autowired
    private SecurityProperties securityProperties;
    public void webReqConnection(RequestBean requestBean) {
    public void authCheck(RequestBean requestBean) {
        Channel channel = ChannelManager.findWebSocketChannel(requestBean.getChannelId());
        channel.writeAndFlush(NettyTools.webSocketBytes("this is ok"));
    }
        ResponseBean responseBean = new ResponseBean();
        responseBean.setType(requestBean.getType());
        responseBean.setStatus(1);
    public void reqHomeSymbols(RequestBean requestBean) {
        String params = requestBean.getParams();
        JSONObject jsonObject = JSONObject.parseObject(params);
        String token = jsonObject.getString("token");
        String type = jsonObject.getString("type");
        ResponseBean responseBean = ResponseBean.ok(requestBean.getType(), null);
        String token = requestBean.getData().toString();
        String redisKey = AppContants.APP_LOGIN_PREFIX + token;
        String loginStr = redisUtils.getString(redisKey);
        if (StrUtil.isBlank(loginStr)) {
            ResponseBean res = ResponseBean.fail();
            res.setType(requestBean.getType());
            channel.writeAndFlush(NettyTools.webSocketBytes(JSONObject.toJSONString(res)));
            return;
        }
        Channel channel = ChannelManager.findWebSocketChannel(requestBean.getChannelId());
        MemberEntity loginUser = JSONObject.parseObject(loginStr, MemberEntity.class);
        Long memberId = loginUser.getId();
        channel.writeAndFlush(NettyTools.webSocketBytes(JSONObject.toJSONString(responseBean)));
        ChannelManager.addWsChannel(channel, memberId);
        String value = redisUtils.getString(AppContants.MSG_NOTICE + memberId);
        if (StrUtil.isNotBlank(value)) {
            responseBean.setType(3);
            responseBean.setData(Integer.parseInt(value));
            channel.writeAndFlush(NettyTools.webSocketBytes(JSONObject.toJSONString(responseBean)));
            redisUtils.del(AppContants.MSG_NOTICE + memberId);
        }
    }
    public void defaultReq(RequestBean requestBean) {
    public void sendMsg(RequestBean requestBean) {
        String chatStr = requestBean.getData().toString();
        log.info("接收到的消息:{}", chatStr);
        ChatRequest chat = JSONObject.parseObject(chatStr, ChatRequest.class);
        Channel channel = ChannelManager.findWebSocketChannel(requestBean.getChannelId());
        channel.writeAndFlush("this is error type");
        ResponseBean res = ResponseBean.ok(chat);
        chat.setTimestamp(System.currentTimeMillis());
        res.setType(2);
        channel.writeAndFlush(NettyTools.webSocketJson(res));
        // 判断是否在线
        Channel targetChannel = ChannelManager.findWsChannel(chat.getTargetId());
        if (targetChannel != null) {
            chat.setIsSelf(2);
            ResponseBean toRes = ResponseBean.ok(chat);
            toRes.setType(2);
            targetChannel.writeAndFlush(NettyTools.webSocketJson(toRes));
        } else {
            // 在redis中保存用户未在线时,给该用户发送的消息条数
//            String key = AppContants.MSG_NOTICE + chat.getTargetId();
//            String value = redisUtils.getString(key);
//            if (StrUtil.isEmpty(value)) {
//                redisUtils.set(key , 1);
//            } else {
//                redisUtils.set(key, Integer.parseInt(value) + 1);
//            }
        }
        chatProducer.sendMsgHistory(chat);
    }
}
src/main/java/com/xcong/excoin/netty/logic/impl/MsgLogicImpl.java
@@ -1,9 +1,13 @@
package com.xcong.excoin.netty.logic.impl;
import cn.hutool.core.util.StrUtil;
import com.xcong.excoin.netty.bean.RequestBean;
import com.xcong.excoin.netty.common.ChannelManager;
import com.xcong.excoin.netty.common.Contans;
import com.xcong.excoin.netty.common.NettyTools;
import com.xcong.excoin.netty.logic.MsgLogic;
import com.xcong.excoin.netty.logic.WebSocketLogic;
import io.netty.channel.Channel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -20,14 +24,14 @@
    @Override
    public void webSocketMsgLogic(RequestBean requestBean) {
        switch (requestBean.getType()) {
            case Contans.WEB_REQ_CONNECTION :
                webSocketLogic.webReqConnection(requestBean);
            case Contans.AUTH_CHECK:
                webSocketLogic.authCheck(requestBean);
                break;
            case Contans.HOME_SYMBOLS:
                webSocketLogic.reqHomeSymbols(requestBean);
            case Contans.MESSAGE:
                webSocketLogic.sendMsg(requestBean);
            default:
                webSocketLogic.defaultReq(requestBean);
                break;
        }
    }
src/main/java/com/xcong/excoin/netty/server/WebSocketServer.java
@@ -19,27 +19,26 @@
@Component("webSocketServer")
public class WebSocketServer implements ChatServer {
    private EventLoopGroup boss = new NioEventLoopGroup();
    private EventLoopGroup work = new NioEventLoopGroup();
    private ChannelFuture channelFuture;
    @Autowired
    private WebSocketServerInitializer webSocketServerInitializer;
//    @Autowired
//    private WebSocketServerInitializer webSocketServerInitializer;
    @Override
    public void start() throws Exception {
        log.info("[websocket服务器启动]");
        log.info("[netty websocket服务器启动]");
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(boss, work)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(webSocketServerInitializer);
                    .childHandler(new WebSocketServerInitializer());
            channelFuture = b.bind(9999).sync();
            channelFuture = b.bind(9998).sync();
            log.info("[websocket服务器启动完成]-->{}", channelFuture.channel().localAddress());
            log.info("[netty websocket服务器启动完成 : {}]", channelFuture.channel().localAddress());
        } finally {
            Runtime.getRuntime().addShutdownHook(new Thread() {
                @Override
src/main/java/com/xcong/excoin/quartz/job/NettyServerStartUp.java
New file
@@ -0,0 +1,21 @@
package com.xcong.excoin.quartz.job;
import com.xcong.excoin.netty.server.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
@Component
@ConditionalOnProperty(prefix = "app", name = "netty-job", havingValue = "true")
public class NettyServerStartUp implements CommandLineRunner {
    @Autowired
    private WebSocketServer webSocketServer;
    @Override
    public void run(String... args) throws Exception {
        webSocketServer.start();
    }
}
src/main/java/com/xcong/excoin/quartz/job/OtcOrderJob.java
New file
@@ -0,0 +1,131 @@
package com.xcong.excoin.quartz.job;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.xcong.excoin.common.contants.AppContants;
import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
import com.xcong.excoin.modules.otc.dao.OtcEntrustOrderDao;
import com.xcong.excoin.modules.otc.dao.OtcMarketBussinessDao;
import com.xcong.excoin.modules.otc.dao.OtcOrderDao;
import com.xcong.excoin.modules.otc.dao.OtcSettingDao;
import com.xcong.excoin.modules.otc.entity.OtcEntrustOrder;
import com.xcong.excoin.modules.otc.entity.OtcMarketBussiness;
import com.xcong.excoin.modules.otc.entity.OtcOrder;
import com.xcong.excoin.modules.otc.entity.OtcSetting;
import com.xcong.excoin.modules.otc.service.OtcOrderService;
import com.xcong.excoin.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@Slf4j
@Component
@ConditionalOnProperty(prefix = "app", name = "otc-job", havingValue = "true")
public class OtcOrderJob {
    @Autowired
    private OtcOrderDao otcOrderDao;
    @Autowired
    private OtcEntrustOrderDao otcEntrustOrderDao;
    @Autowired
    private OtcMarketBussinessDao otcMarketBussinessDao;
    @Autowired
    private MemberWalletCoinDao memberWalletCoinDao;
    @Autowired
    private OtcSettingDao otcSettingDao;
    @Autowired
    private RedisUtils redisUtils;
    @Scheduled(cron = "0/1 * * * * ? ")
    public void autoCancelOrder() {
        List<OtcOrder> otcOrders = otcOrderDao.selectOrderListWithStatusAndType(OtcEntrustOrder.ORDER_TYPE_B, OtcOrder.STATUS_SUBMIT);
        if (CollUtil.isNotEmpty(otcOrders)) {
            for (OtcOrder otcOrder : otcOrders) {
                long between = DateUtil.between(new Date(), DateUtil.offsetMinute(otcOrder.getCreateTime(), 30), DateUnit.SECOND, false);
                if (between <= 0) {
                    OtcOrder saleOrder = otcOrderDao.selectOrderByOrderNoAndType(otcOrder.getOrderNo(), OtcEntrustOrder.ORDER_TYPE_S);
                    if (!saleOrder.getMemberId().equals(saleOrder.getEntrustMemberId())) {
                        MemberWalletCoinEntity wallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(saleOrder.getMemberId(), "USDT");
                        memberWalletCoinDao.subFrozenBalance(saleOrder.getMemberId(), wallet.getId(), saleOrder.getCoinAmount());
                    }
                    otcEntrustOrderDao.updateRemainAmount(otcOrder.getEntrustOrderId(), otcOrder.getCoinAmount());
                    otcOrderDao.updateOrderStatusByOrderNo(OtcOrder.STATUS_CANCEL, null, otcOrder.getOrderNo());
                    Long memberId;
                    if (otcOrder.getMemberId().equals(otcOrder.getEntrustMemberId())) {
                        memberId = otcOrder.getOppositeMemberId();
                    } else {
                        memberId = otcOrder.getMemberId();
                    }
                    OtcSetting setting = otcSettingDao.selectById(1L);
                    String times = redisUtils.getString(AppContants.OTC_ORDER_CANCEL_TIMES + memberId);
                    if (StrUtil.isNotBlank(times)) {
                        int i = Integer.parseInt(times);
                        i++;
                        if (i >= setting.getCancellNum()) {
                            redisUtils.set(AppContants.OTC_ORDER_CANCEL_TIMES + memberId, i, 86400);
                        } else {
                            redisUtils.set(AppContants.OTC_ORDER_CANCEL_TIMES + memberId, i);
                        }
                    } else {
                        redisUtils.set(AppContants.OTC_ORDER_CANCEL_TIMES + memberId, 1, 86400);
                    }
                }
            }
        }
    }
//    @Scheduled(cron = "0 0/5 * * * ? ")
    public void marketBussinessJob() {
        List<OtcMarketBussiness> list = otcMarketBussinessDao.selectList(null);
        if (CollUtil.isNotEmpty(list)) {
            for (OtcMarketBussiness mb : list) {
                // 服务人数
                Integer buyCnt = otcOrderDao.selectMemberCntForEntrust(mb.getMemberId());
                // 买单数
                Integer buyTotalCnt = otcOrderDao.selectTotalOrderCount(mb.getMemberId(), null, OtcEntrustOrder.ORDER_TYPE_B);
                // 买单完成率
                Integer buyFinishCnt = otcOrderDao.selectTotalOrderCount(mb.getMemberId(), OtcOrder.STATUS_FINISH, OtcEntrustOrder.ORDER_TYPE_B);
                if (buyTotalCnt != null && buyTotalCnt != 0) {
                    BigDecimal finishRatio = BigDecimal.valueOf(buyFinishCnt).divide(BigDecimal.valueOf(buyTotalCnt), 4, BigDecimal.ROUND_DOWN);
                    mb.setFinishRatio(finishRatio);
                }
                // 买单数
                Integer saleTotalCnt = otcOrderDao.selectTotalOrderCount(mb.getMemberId(), null, OtcEntrustOrder.ORDER_TYPE_S);
                // 买单完成率
                Integer saleFinishCnt = otcOrderDao.selectTotalOrderCount(mb.getMemberId(), OtcOrder.STATUS_FINISH, OtcEntrustOrder.ORDER_TYPE_S);
                if (saleTotalCnt != null && saleTotalCnt != 0) {
                    BigDecimal finishRatio = BigDecimal.valueOf(saleFinishCnt).divide(BigDecimal.valueOf(saleTotalCnt), 4, BigDecimal.ROUND_DOWN);
                    mb.setSaleFinishRatio(finishRatio);
                }
                // 平均付款时间
                BigDecimal avgPayTime = otcOrderDao.selectMemberAvgPayTime(mb.getMemberId());
                // 平均放币时间
                BigDecimal avgCoinTime = otcOrderDao.selectMemberAvgCoinTime(mb.getMemberId());
                mb.setBuyCnt(buyCnt);
                mb.setTotalOrderCnt(buyTotalCnt);
                mb.setSaleOrderCnt(saleTotalCnt);
                mb.setAvgPayTime(avgPayTime.intValue());
                mb.setAvgCoinTime(avgCoinTime.intValue());
                otcMarketBussinessDao.updateById(mb);
            }
        }
    }
}
src/main/java/com/xcong/excoin/rabbit/consumer/ChatConsumer.java
New file
@@ -0,0 +1,106 @@
package com.xcong.excoin.rabbit.consumer;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.xcong.excoin.common.contants.AppContants;
import com.xcong.excoin.configurations.RabbitMqConfig;
import com.xcong.excoin.modules.member.dao.MemberSettingDao;
import com.xcong.excoin.modules.otc.dao.OtcMsgHistoryDao;
import com.xcong.excoin.modules.otc.dao.OtcMsgUserListDao;
import com.xcong.excoin.modules.otc.entity.OtcMsgHistoryEntity;
import com.xcong.excoin.modules.otc.entity.OtcMsgUserListEntity;
import com.xcong.excoin.netty.bean.ChatRequest;
import com.xcong.excoin.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
@Slf4j
@Component
@ConditionalOnProperty(prefix = "app", name = "netty-job", havingValue = "true")
public class ChatConsumer {
    @Autowired
    private OtcMsgUserListDao otcMsgUserListDao;
    @Autowired
    private OtcMsgHistoryDao otcMsgHistoryDao;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private MemberSettingDao memberSettingDao;
    @RabbitListener(queues = RabbitMqConfig.QUEUE_MSG_HISTORY)
    @Transactional(rollbackFor = Exception.class)
    public void msgHistoryConsumer(String content) {
        log.info("收到历史消息处理:{}", content);
        ChatRequest chat = JSONObject.parseObject(content, ChatRequest.class);
        Long toId = chat.getTargetId();
        Long fromId = chat.getFromMemberId();
        // 发送人是否存在聊天框
        OtcMsgUserListEntity fromList = otcMsgUserListDao.selectChatListByToAndFrom(toId, fromId);
        if (fromList == null) {
            OtcMsgUserListEntity from = new OtcMsgUserListEntity();
            from.setMemberId(fromId);
            from.setTargetId(toId);
            from.setIsRead(OtcMsgUserListEntity.ISREAD_TWO);
            from.setLastMsgTime(new Date());
            otcMsgUserListDao.insert(from);
        } else {
            fromList.setLastMsgTime(new Date());
            otcMsgUserListDao.updateById(fromList);
        }
        // 收件人是否存在聊天框
        OtcMsgUserListEntity toList = otcMsgUserListDao.selectChatListByToAndFrom(fromId, toId);
        if (toList == null) {
            OtcMsgUserListEntity from = new OtcMsgUserListEntity();
            from.setMemberId(toId);
            from.setTargetId(fromId);
            from.setIsRead(OtcMsgUserListEntity.ISREAD_ONE);
            from.setLastMsgTime(new Date());
            otcMsgUserListDao.insert(from);
        } else {
            // 收件人正在聊的用户
            String value = redisUtils.getString(AppContants.MSG_CHATTING + toId);
            if (StrUtil.isNotBlank(value) && value.equals(fromId.toString())) {
                toList.setLastMsgTime(new Date());
                otcMsgUserListDao.updateById(toList);
            } else {
                toList.setIsRead(OtcMsgUserListEntity.ISREAD_ONE);
                toList.setLastMsgTime(new Date());
                otcMsgUserListDao.updateById(toList);
            }
        }
        OtcMsgHistoryEntity toHistory = new OtcMsgHistoryEntity();
        toHistory.setMemberId(toId);
        toHistory.setFromMemberId(fromId);
        toHistory.setTargetId(toId);
        toHistory.setIsSelf(OtcMsgHistoryEntity.ISSELF_TWO);
        toHistory.setMsgType(chat.getMsgType());
        toHistory.setMsg(chat.getMsg());
        OtcMsgHistoryEntity fromHistory = new OtcMsgHistoryEntity();
        BeanUtil.copyProperties(toHistory, fromHistory);
        fromHistory.setIsSelf(OtcMsgHistoryEntity.ISSELF_ONE);
        fromHistory.setMemberId(fromId);
        memberSettingDao.updateMessageReminderByMemberId(toId);
        otcMsgHistoryDao.insert(fromHistory);
        otcMsgHistoryDao.insert(toHistory);
    }
}
src/main/java/com/xcong/excoin/rabbit/consumer/OtcConsumer.java
New file
@@ -0,0 +1,161 @@
package com.xcong.excoin.rabbit.consumer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.xcong.excoin.configurations.RabbitMqConfig;
import com.xcong.excoin.modules.member.dao.MemberDao;
import com.xcong.excoin.modules.member.dao.MemberSettingDao;
import com.xcong.excoin.modules.member.dao.MemberWalletCoinDao;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.member.entity.MemberSettingEntity;
import com.xcong.excoin.modules.member.entity.MemberWalletCoinEntity;
import com.xcong.excoin.modules.otc.dao.OtcEntrustOrderDao;
import com.xcong.excoin.modules.otc.dao.OtcMarketBussinessDao;
import com.xcong.excoin.modules.otc.dao.OtcOrderDao;
import com.xcong.excoin.modules.otc.dao.OtcReturnMoneyDao;
import com.xcong.excoin.modules.otc.entity.OtcEntrustOrder;
import com.xcong.excoin.modules.otc.entity.OtcMarketBussiness;
import com.xcong.excoin.modules.otc.entity.OtcOrder;
import com.xcong.excoin.modules.otc.entity.OtcReturnMoney;
import com.xcong.excoin.utils.LogRecordUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
@ConditionalOnProperty(prefix = "app", name = "otc-job", havingValue = "true")
public class OtcConsumer {
    @Autowired
    private OtcMarketBussinessDao otcMarketBussinessDao;
    @Autowired
    private OtcEntrustOrderDao otcEntrustOrderDao;
    @Autowired
    private OtcOrderDao otcOrderDao;
    @Autowired
    private MemberDao memberDao;
    @Autowired
    private MemberSettingDao memberSettingDao;
    @Autowired
    private MemberWalletCoinDao memberWalletCoinDao;
    @Autowired
    private OtcReturnMoneyDao otcReturnMoneyDao;
    @RabbitListener(queues = RabbitMqConfig.QUEUE_MARKET_BUSSINESS)
    public void marketBussiness(String content) {
        log.info("收到市商消息:{}", content);
        JSONObject jsonObject = JSONObject.parseObject(content);
        Integer entrustOrderIdInt = jsonObject.getInteger("entrustOrderId");
        Long entrustOrderId = entrustOrderIdInt.longValue();
        Integer status = jsonObject.getInteger("status");
        OtcEntrustOrder entrustOrder = otcEntrustOrderDao.selectById(entrustOrderId);
        OtcMarketBussiness mb = otcMarketBussinessDao.selectMarketBussinessByMemberId(entrustOrder.getMemberId());
        if (!OtcOrder.STATUS_CANCEL.equals(status)) {
            if (OtcEntrustOrder.ORDER_TYPE_S.equals(entrustOrder.getOrderType())) {
                mb.setSaleOrderCnt(mb.getSaleOrderCnt() + 1);
                mb.setSaleTotalCnt(mb.getSaleTotalCnt() + 1);
            } else {
                mb.setBuyOrderCnt(mb.getBuyOrderCnt() + 1);
                mb.setTotalOrderCnt(mb.getTotalOrderCnt() + 1);
            }
        } else {
            if (OtcEntrustOrder.ORDER_TYPE_S.equals(entrustOrder.getOrderType())) {
                mb.setSaleTotalCnt(mb.getSaleTotalCnt() + 1);
            } else {
                mb.setTotalOrderCnt(mb.getTotalOrderCnt() + 1);
            }
        }
        if (mb.getTotalOrderCnt() != 0) {
            BigDecimal buyFinishRatio = BigDecimal.valueOf(mb.getBuyOrderCnt()).divide(BigDecimal.valueOf(mb.getTotalOrderCnt()), 8, BigDecimal.ROUND_DOWN);
            mb.setFinishRatio(buyFinishRatio);
        }
        if (mb.getSaleTotalCnt() != 0) {
            BigDecimal saleFinishRatio = BigDecimal.valueOf(mb.getSaleOrderCnt()).divide(BigDecimal.valueOf(mb.getSaleTotalCnt()), 8, BigDecimal.ROUND_DOWN);
            mb.setSaleFinishRatio(saleFinishRatio);
        }
        // 平均付款时间
//        BigDecimal avgPayTime = otcOrderDao.selectMemberAvgPayTime(mb.getMemberId());
//        // 平均放币时间
//        BigDecimal avgCoinTime = otcOrderDao.selectMemberAvgCoinTime(mb.getMemberId());
//
//        mb.setAvgPayTime(avgPayTime.intValue());
//        mb.setAvgCoinTime(avgCoinTime.intValue());
        otcMarketBussinessDao.updateById(mb);
    }
//    @RabbitListener(queues = RabbitMqConfig.QUEUE_MARKET_BUSSINESS)
    public void delayOrder(String content) {
        log.info("--{}-->{}", new Date(), content);
    }
//    @RabbitListener(queues = RabbitMqConfig.QUEUE_ORDER_RETURN)
//    @Transactional(rollbackFor = Exception.class)
//    public void orderReturn(String content) {
//        log.info("收到返佣消息:{}", content);
//        OtcOrder order = otcOrderDao.selectOrderUnEntrust(content);
//
//        MemberEntity member = memberDao.selectById(order.getMemberId());
//        List<String> refererIds = StrUtil.split(member.getRefererIds(), ',');
//
//        List<MemberEntity> parentMembers = memberDao.selectMemberListByReferer(refererIds);
//
//        if (CollUtil.isNotEmpty(parentMembers)) {
//            int isFirst = 1;
//            for (MemberEntity parent : parentMembers) {
//                MemberSettingEntity memberSetting = memberSettingDao.selectMemberSettingByMemberId(parent.getId());
//
//                BigDecimal returnRatio = BigDecimal.ZERO;
//                if (isFirst == 1) {
//                    returnRatio = memberSetting.getOtcReturnFirst();
//                } else {
//                    returnRatio = memberSetting.getOtcReturnSecond();
//                }
//
//                BigDecimal returnAmount = order.getCoinAmount().multiply(returnRatio);
//
//                MemberWalletCoinEntity wallet = memberWalletCoinDao.selectWalletCoinBymIdAndCode(parent.getId(), "USDT");
//                memberWalletCoinDao.updateBlockBalance(wallet.getId(), returnAmount, BigDecimal.ZERO, 0);
//
//                LogRecordUtils.insertMemberAccountMoneyChange(parent.getId(),"订单返利:" + content, returnAmount, "USDT", 1, 1);
//
//                OtcReturnMoney otcReturnMoney = new OtcReturnMoney();
//                otcReturnMoney.setToMemberId(parent.getId());
//                otcReturnMoney.setOrderNo(content);
//                otcReturnMoney.setFromMemberId(member.getId());
//                otcReturnMoney.setAmount(returnAmount);
//                otcReturnMoneyDao.insert(otcReturnMoney);
//
//                isFirst = 0;
//            }
//        }
//
//        order.setIsReturn(1);
//        otcOrderDao.updateIsReturnByOrderNo(1, content);
//    }
}
src/main/java/com/xcong/excoin/rabbit/producer/ChatProducer.java
New file
@@ -0,0 +1,33 @@
package com.xcong.excoin.rabbit.producer;
import com.alibaba.fastjson.JSONObject;
import com.xcong.excoin.configurations.RabbitMqConfig;
import com.xcong.excoin.netty.bean.ChatRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.UUID;
@Slf4j
@Component
public class ChatProducer implements RabbitTemplate.ConfirmCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    public void sendMsgHistory(ChatRequest chatRequest) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        log.info("消息持久化消息: {}, {}", chatRequest, correlationData.getId());
        String str = JSONObject.toJSONString(chatRequest);
        rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_ONE, RabbitMqConfig.ROUTING_KEY_MSG_HISTORY, str, correlationData);
    }
    @Override
    public void confirm(CorrelationData correlationData, boolean b, String s) {
    }
}
src/main/java/com/xcong/excoin/rabbit/producer/OtcProducter.java
New file
@@ -0,0 +1,68 @@
package com.xcong.excoin.rabbit.producer;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.xcong.excoin.configurations.RabbitMqConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Component
public class OtcProducter implements RabbitTemplate.ConfirmCallback {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    public OtcProducter(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
        rabbitTemplate.setConfirmCallback(this);
    }
    public void sendMarketBussinessMsg(Long entrustOrderId, Integer status) {
        log.info("发送市商消息");
        CorrelationData correlationData = new CorrelationData(IdUtil.simpleUUID());
        Map<String, Object> map = new HashMap<>();
        map.put("entrustOrderId", entrustOrderId);
        map.put("status", status);
        String s = JSONObject.toJSONString(map);
        rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_ONE, RabbitMqConfig.ROUTINGKEY_MARKET_BUSSINESS, s, correlationData);
    }
//
//    public void sendDelayOrderMsg(String content) {
//        log.info("-----{}", new Date());
//        CorrelationData correlationData = new CorrelationData(IdUtil.simpleUUID());
//        rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_DELAY, RabbitMqConfig.ROUTING_KEY_DELAY, content, message -> {
//            message.getMessageProperties().setExpiration(6000 + "");
//            return message;
//        });
//    }
    public void sendOrderReturn(String content) {
        log.info("发送返佣消息");
        CorrelationData correlationData = new CorrelationData(IdUtil.simpleUUID());
        rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_ONE, RabbitMqConfig.ROUTING_ORDER_RETURN, content, correlationData);
    }
    @Override
    public void confirm(CorrelationData correlationData, boolean b, String s) {
    }
}
src/main/java/com/xcong/excoin/utils/ThreadPoolUtils.java
@@ -47,4 +47,13 @@
            }
        });
    }
    public static void sendOrderMsg() {
        EXECUTOR.execute(new Runnable() {
            @Override
            public void run() {
                DingTalkUtils.sendOrderMsg();
            }
        });
    }
}
src/main/java/com/xcong/excoin/utils/dingtalk/DingTalkUtils.java
@@ -1,10 +1,13 @@
package com.xcong.excoin.utils.dingtalk;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.dingtalk.api.response.OapiRobotSendResponse;
import com.xcong.excoin.configurations.properties.ApplicationProperties;
import com.xcong.excoin.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
@@ -20,23 +23,31 @@
 **/
@Slf4j
public class DingTalkUtils {
    private static final String SECRET = "SECbc84fd6c2edb9f2f440f9f969981ca310ba553e7c7994cf68cf26e4607cc5943";
    private static final String URL = "https://oapi.dingtalk.com/robot/send?access_token=54a0d627111f3667f7e98691c15becadb742c4da895e60f6d77392389e49658a";
    private static final String SECRET = "SECc0b73559742b950f07eabbd050c406a6abb3b67d112d3735289e90f58884c543";
    private static final String EXCEPTION_URL = "https://oapi.dingtalk.com/robot/send?access_token=da71769f2b21fe2004f00980a8d8e9c4b9db76a0b8025b6f4d957f55653fea39";
    private static final String EXCEPTION_SECRET = "SECd9169511c38c3643bbda2440b1dcd1d3a57203656186fc2ceb7fcbef18c777ed";
    private static DingTalkClient initClient(String url, String secret) throws Exception {
        Long timestamp = System.currentTimeMillis();
        String sign = generateSign(timestamp, secret);
        url = url + "&timestamp=" + timestamp + "&sign=" + sign;
        return new DefaultDingTalkClient(url);
    }
    public static void sendActionCard(int type) {
        log.info("send dingtalk");
        String url = "https://oapi.dingtalk.com/robot/send?access_token=161d5e5b60ae5d6b4c80f2a9c35f9f212961a7c7154aa7e94b99503eca3886b0";
        Long timestamp = System.currentTimeMillis();
        ApplicationProperties properties = SpringContextHolder.getBean(ApplicationProperties.class);
        try {
            String sign = generateSign(timestamp);
            url = url + "&timestamp=" + timestamp + "&sign=" + sign;
            DingTalkClient client = new DefaultDingTalkClient(url);
            DingTalkClient client = initClient(URL, SECRET);
            OapiRobotSendRequest request = new OapiRobotSendRequest();
            request.setMsgtype("actionCard");
            OapiRobotSendRequest.Actioncard actionCard = new OapiRobotSendRequest.Actioncard();
            actionCard.setTitle(DingTalkType.getName(type));
            actionCard.setTitle(properties.getProject() + "--" + DingTalkType.getName(type));
            actionCard.setBtnOrientation("1");
            actionCard.setText(DingTalkType.getName(type));
            actionCard.setText(properties.getProject() + "--" + DingTalkType.getName(type));
            List<OapiRobotSendRequest.Btns> btns = new ArrayList<>();
            OapiRobotSendRequest.Btns btn1 = new OapiRobotSendRequest.Btns();
            btn1.setTitle("查看详情");
@@ -46,22 +57,70 @@
            request.setActionCard(actionCard);
            OapiRobotSendResponse response = client.execute(request);
            //log.info(JSONObject.toJSONString(response));
            log.info(JSONObject.toJSONString(response));
        } catch (Exception e) {
            log.error("#dingtalk send error#", e);
        } finally {
            log.error("#dingtalk finally#");
        }
    }
    public static void sendMsg(String title, String msg, Long id) {
        try {
            String text = "### {} \n\n {}";
            DingTalkClient client = initClient(EXCEPTION_URL, EXCEPTION_SECRET);
            OapiRobotSendRequest request = new OapiRobotSendRequest();
            request.setMsgtype("actionCard");
            OapiRobotSendRequest.Actioncard actionCard = new OapiRobotSendRequest.Actioncard();
            actionCard.setTitle("异常消息");
            actionCard.setBtnOrientation("0");
            actionCard.setText(StrUtil.format(text, title, msg));
            actionCard.setSingleURL("http://api.topclouds.cc/common/getExceptionMsg?id=" + id);
            actionCard.setSingleTitle("查询详情");
            request.setActionCard(actionCard);
            OapiRobotSendResponse response = client.execute(request);
            log.info(JSONObject.toJSONString(response));
        } catch (Exception e) {
            log.error("#dingtalk send error#", e);
        }
    }
    public static void sendOrderMsg() {
        ApplicationProperties properties = SpringContextHolder.getBean(ApplicationProperties.class);
        try {
            DingTalkClient client = initClient(URL, SECRET);
            OapiRobotSendRequest request = new OapiRobotSendRequest();
            request.setMsgtype("actionCard");
            OapiRobotSendRequest.Actioncard actionCard = new OapiRobotSendRequest.Actioncard();
            actionCard.setTitle(properties.getProject() + "--" + "老板开门啊");
            actionCard.setBtnOrientation("1");
            actionCard.setText(properties.getProject() + "--" + "老板关门不好吧");
            List<OapiRobotSendRequest.Btns> btns = new ArrayList<>();
            OapiRobotSendRequest.Btns btn1 = new OapiRobotSendRequest.Btns();
            btn1.setTitle("查看详情");
            btn1.setActionURL("http://baidu.com");
            btns.add(btn1);
            actionCard.setBtns(btns);
            request.setActionCard(actionCard);
            client.execute(request);
        } catch (Exception e) {
            log.error("#dingtalk send error#", e);
        }
    }
    private static String generateSign(Long timestamp) throws Exception {
        String stringToToken = timestamp + "\n" + SECRET;
    private static String generateSign(Long timestamp, String secret) throws Exception {
        String stringToToken = timestamp + "\n" + secret;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(SECRET.getBytes("UTF-8"), "HmacSHA256"));
        mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
        byte[] signData = mac.doFinal(stringToToken.getBytes("UTF-8"));
        String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
        return sign;
    }
    public static void main(String[] args) {
//        sendMsg("测试一下", "内容");
    }
}
src/main/resources/application-prod.yml
@@ -92,6 +92,7 @@
app:
  debug: false
  project: otc
  redis_expire: 3000
  kline-update-job: false
  newest-price-update-job: true
@@ -101,6 +102,8 @@
  loop-job: true
  rabbit-consumer: true
  block-job: true
  netty-job: true
  otc-job: true
aliyun:
  oss:
src/main/resources/application-prodapp.yml
@@ -92,6 +92,7 @@
app:
  debug: false
  project: otc
  redis_expire: 3000
  kline-update-job: false
  newest-price-update-job: false
@@ -101,6 +102,8 @@
  loop-job: false
  rabbit-consumer: false
  block-job: false
  netty-job: false
  otc-job: false
aliyun:
  oss:
src/main/resources/application.yml
@@ -92,6 +92,7 @@
app:
  debug: true
  project: otc
  redis_expire: 3000
  kline-update-job: false
  newest-price-update-job: false
@@ -101,6 +102,8 @@
  loop-job: false
  rabbit-consumer: false
  block-job: false
  netty-job: false
  otc-job: false
aliyun:
  oss:
src/main/resources/mapper/member/MemberPaymentMethodDao.xml
@@ -5,4 +5,19 @@
    <select id="selectByMemberId" resultType="com.xcong.excoin.modules.member.entity.MemberPaymentMethodEntity">
        SELECT a.* FROM member_payment_method a WHERE a.member_id = #{memberId}
    </select>
    <select id="selectDefualtMethod" resultType="com.xcong.excoin.modules.member.entity.MemberPaymentMethodEntity">
        select * from member_payment_method
        <where>
            <if test="memberId != null">
                and member_id=#{memberId}
            </if>
            <if test="isDefault != null and isDefault != ''">
                and is_defualt = #{isDefault}
            </if>
            <if test="type != null">
                and payment_type = #{type}
            </if>
        </where>
    </select>
</mapper>
src/main/resources/mapper/member/MemberSettingDao.xml
@@ -35,4 +35,10 @@
        </foreach>
    </insert>
    <update id="updateMessageReminderByMemberId">
        UPDATE member_setting s
        SET s.message_reminder = 1
        WHERE
            member_id = #{memberId}
    </update>
</mapper>
src/main/resources/mapper/member/MemberWalletCoinDao.xml
@@ -61,5 +61,11 @@
        where id=#{id}
    </update>
    <update id="reduceFrozenBalance">
        update member_wallet_coin
        set frozen_balance = frozen_balance - #{amount},
            total_balance = total_balance - #{amount}
        where id=#{id}
    </update>
</mapper>