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.*; @@ -211,6 +212,21 @@ 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(); } /** * 绑定手机号 * @return 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); 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; } 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); MemberEntity loginUser = JSONObject.parseObject(loginStr, MemberEntity.class); Long memberId = loginUser.getId(); Channel channel = ChannelManager.findWebSocketChannel(requestBean.getChannelId()); 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 + "×tamp=" + 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 + "×tamp=" + 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>