|
|
@@ -0,0 +1,345 @@
|
|
|
+package com.bex.staking.controller;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.bex.common.model.R;
|
|
|
+import com.bex.staking.model.dto.StakingOrderQuery;
|
|
|
+import com.bex.staking.model.vo.*;
|
|
|
+import com.bex.staking.service.StakingService;
|
|
|
+import jakarta.validation.Valid;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@RestController
|
|
|
+@RequestMapping("/api/v1/staking")
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class StakingController {
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取质押首页信息
|
|
|
+ * @param userId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @GetMapping("/home")
|
|
|
+ public R<StakingHomeVO> stake(
|
|
|
+ @RequestHeader("X-User-Id") Long userId) {
|
|
|
+ StakingHomeVO vo = new StakingHomeVO();
|
|
|
+ // 1. 用户资产 mock
|
|
|
+ vo.setAvailableBalance("124494.01");
|
|
|
+ vo.setAvailableUnit("BEX");
|
|
|
+ vo.setTotalProfit("801.41");
|
|
|
+ vo.setTotalProfitUnit("BEX");
|
|
|
+ vo.setPendingProfit("33.49");
|
|
|
+ vo.setPendingProfitUnit("BEX");
|
|
|
+ vo.setSettleRule("每日10:00 结算收益到待领取,点击领取后到账。累计收益达到本金 80% 时,到期可能触发通缩赎回。");
|
|
|
+ return R.success(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取推荐质押产品列表
|
|
|
+ * @param page
|
|
|
+ * @param size
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @GetMapping("/recommendationPage")
|
|
|
+ public R<Page<StakingProductVO>> list(
|
|
|
+ @RequestParam(value = "page", defaultValue = "1") Integer page,
|
|
|
+ @RequestParam(value = "size", defaultValue = "10") Integer size,
|
|
|
+ @RequestParam(value = "isRecommendation", defaultValue = "true") Boolean isRecommendation) {
|
|
|
+
|
|
|
+ Page<StakingProductVO> pageData = new Page<>(page, size);
|
|
|
+ List<StakingProductVO> productList = new ArrayList<>();
|
|
|
+
|
|
|
+ if (isRecommendation) {
|
|
|
+
|
|
|
+ StakingProductVO p1 = new StakingProductVO();
|
|
|
+ p1.setProductId("1001");
|
|
|
+ p1.setProductName("BEX 3个月质押");
|
|
|
+ p1.setApr("24%");
|
|
|
+ p1.setStatus("可质押");
|
|
|
+ p1.setPeriodRate("6.0000%");
|
|
|
+ p1.setProfitMode("10点结算");
|
|
|
+ p1.setMinInvestNum("100 BEX");
|
|
|
+ p1.setThresholdRule("80% 通缩");
|
|
|
+ p1.setLockDay(90);
|
|
|
+
|
|
|
+ StakingProductVO p2 = new StakingProductVO();
|
|
|
+ p2.setProductId("1002");
|
|
|
+ p2.setProductName("BEX 6个月质押");
|
|
|
+ p2.setApr("34%");
|
|
|
+ p2.setStatus("可质押");
|
|
|
+ p2.setPeriodRate("6.0000%");
|
|
|
+ p2.setProfitMode("10点结算");
|
|
|
+ p2.setMinInvestNum("100 BEX");
|
|
|
+ p2.setThresholdRule("80% 通缩");
|
|
|
+ p2.setLockDay(180);
|
|
|
+
|
|
|
+ productList.add(p1);
|
|
|
+ productList.add(p2);
|
|
|
+ pageData.setRecords(productList);
|
|
|
+ } else {
|
|
|
+ // 1. BEX 3个月质押 - 可质押
|
|
|
+ StakingProductVO p1 = new StakingProductVO();
|
|
|
+ p1.setProductId("1001");
|
|
|
+ p1.setProductName("BEX 3个月质押");
|
|
|
+ p1.setApr("24%");
|
|
|
+ p1.setStatus("可质押");
|
|
|
+ p1.setPeriodRate("6.0000%");
|
|
|
+ p1.setProfitMode("10点结算");
|
|
|
+ p1.setMinInvestNum("100 BEX");
|
|
|
+ p1.setThresholdRule("80% 通缩");
|
|
|
+ p1.setLockDay(90);
|
|
|
+ p1.setCountDown(null);
|
|
|
+
|
|
|
+ // 2. BEX 6个月质押 - 即将开启(带倒计时)
|
|
|
+ StakingProductVO p2 = new StakingProductVO();
|
|
|
+ p2.setProductId("1002");
|
|
|
+ p2.setProductName("BEX 6个月质押");
|
|
|
+ p2.setApr("44%");
|
|
|
+ p2.setStatus("即将开启");
|
|
|
+ p2.setPeriodRate("6.0000%");
|
|
|
+ p2.setProfitMode("10点结算");
|
|
|
+ p2.setMinInvestNum("100 BEX");
|
|
|
+ p2.setThresholdRule("80% 通缩");
|
|
|
+ p2.setLockDay(180);
|
|
|
+ p2.setCountDown(System.currentTimeMillis() + 36000000L);
|
|
|
+
|
|
|
+ // 3. BEX 6个月质押 - 已结束
|
|
|
+ StakingProductVO p3 = new StakingProductVO();
|
|
|
+ p3.setProductId("1003");
|
|
|
+ p3.setProductName("BEX 6个月质押");
|
|
|
+ p3.setApr("78%");
|
|
|
+ p3.setStatus("已结束");
|
|
|
+ p3.setPeriodRate("6.0000%");
|
|
|
+ p3.setProfitMode("10点结算");
|
|
|
+ p3.setMinInvestNum("100 BEX");
|
|
|
+ p3.setThresholdRule("80% 通缩");
|
|
|
+ p3.setLockDay(180);
|
|
|
+ p3.setCountDown(null);
|
|
|
+
|
|
|
+ productList.add(p1);
|
|
|
+ productList.add(p2);
|
|
|
+ productList.add(p3);
|
|
|
+ pageData.setRecords(productList);
|
|
|
+ }
|
|
|
+ return R.success(pageData);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 质押产品详情接口
|
|
|
+ */
|
|
|
+ @GetMapping("/detail/{id}")
|
|
|
+ public R<StakingProductDetailVO> getProductDetail(@PathVariable("id") Long id) {
|
|
|
+ StakingProductDetailVO vo = new StakingProductDetailVO();
|
|
|
+ // Mock 3个月质押数据
|
|
|
+ vo.setProductId("1001");
|
|
|
+ vo.setProductName("BEX 3个月质押");
|
|
|
+ vo.setStatus("可质押");
|
|
|
+ vo.setIsShowTwap(true);
|
|
|
+ vo.setApr("24%");
|
|
|
+
|
|
|
+ vo.setPeriodDay(90);
|
|
|
+ vo.setPeriodRate("6.0000%");
|
|
|
+ vo.setDailyRate("0.066666%");
|
|
|
+ vo.setMinInvestNum("100 BEX");
|
|
|
+
|
|
|
+ vo.setBaseAmount("1,000 BEX");
|
|
|
+ vo.setDailyProfit("0.666666 BEX");
|
|
|
+ vo.setTotalProfit("60.0000 BEX");
|
|
|
+
|
|
|
+ return R.ok(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 质押预览接口(输入数量后返回预览结果)
|
|
|
+ */
|
|
|
+ @GetMapping("/preview")
|
|
|
+ public R<StakingPreviewVO> stakingPreview(
|
|
|
+ @RequestParam(value = "productId", required = false) Long productId,
|
|
|
+ @RequestParam(value = "stakingNum", required = false) BigDecimal stakingNum
|
|
|
+ ) {
|
|
|
+ StakingPreviewVO vo = new StakingPreviewVO();
|
|
|
+ // 可用资产
|
|
|
+ vo.setAvailableBalance("12,000");
|
|
|
+ vo.setAvailableUnit("BEX");
|
|
|
+ // 价格&价值
|
|
|
+ vo.setEntryPrice("1.250000 USDT");
|
|
|
+ vo.setInitialValue("1,250.0000 USDT");
|
|
|
+ // 收益
|
|
|
+ vo.setDailyProfit("0.666666 BEX");
|
|
|
+ vo.setTotalProfit("60.0000 BEX");
|
|
|
+ vo.setExpireTime(System.currentTimeMillis());
|
|
|
+ vo.setTriggerThreshold("800.0000 BEX");
|
|
|
+ // 文案&规则
|
|
|
+ vo.setRiskTip("我已理解收益按 BEX 计发,若累计收益达到本金 80%,到期可能触发通缩赎回和销毁流程。");
|
|
|
+ vo.setIdempotentTip("创建订单将使用幂等键提交。网络超时后复用同一请求,不生成重复订单。");
|
|
|
+ vo.setValidSecond(30);
|
|
|
+
|
|
|
+ return R.ok(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 我的质押订单列表接口
|
|
|
+ */
|
|
|
+ @PostMapping("/order/page")
|
|
|
+ public R<Page<StakingOrderListVO>> getStakingOrderList(@RequestBody StakingOrderQuery query) {
|
|
|
+ List<StakingOrderListVO> list = new ArrayList<>();
|
|
|
+ Page<StakingOrderListVO> pageData = new Page<>(query.getPage(), query.getSize());
|
|
|
+ // 订单1:进行中 - 3个月质押
|
|
|
+ StakingOrderListVO order1 = new StakingOrderListVO();
|
|
|
+ order1.setOrderId("100001");
|
|
|
+ order1.setProductName("BEX 3个月质押");
|
|
|
+ order1.setOrderNo("STK202605181004150001");
|
|
|
+ order1.setOrderStatus("进行中");
|
|
|
+ order1.setPrincipal("1,000 BEX");
|
|
|
+ order1.setTotalProfit("20 BEX");
|
|
|
+ order1.setExpireTime(System.currentTimeMillis());
|
|
|
+ order1.setProfitMode("10点结算");
|
|
|
+ order1.setProgressPercent(50);
|
|
|
+
|
|
|
+ // 订单2:通缩赎回 - 6个月质押
|
|
|
+ StakingOrderListVO order2 = new StakingOrderListVO();
|
|
|
+ order2.setOrderId("100002");
|
|
|
+ order2.setProductName("BEX 6个月质押");
|
|
|
+ order2.setOrderNo("STK202605181004150001");
|
|
|
+ order2.setOrderStatus("通缩赎回");
|
|
|
+ order2.setReturnPrincipal("1,000 BEX");
|
|
|
+ order2.setBurnAmount("20 BEX");
|
|
|
+ order2.setTotalProfitAmount("1,600 BEX");
|
|
|
+ order2.setStatusDesc("已完成");
|
|
|
+
|
|
|
+ // 订单3:进行中 - 9个月质押
|
|
|
+ StakingOrderListVO order3 = new StakingOrderListVO();
|
|
|
+ order3.setOrderId("100003");
|
|
|
+ order3.setProductName("BEX 9个月质押");
|
|
|
+ order3.setOrderNo("STK202605181004150001");
|
|
|
+ order3.setOrderStatus("进行中");
|
|
|
+ order3.setPrincipal("1,000 BEX");
|
|
|
+ order3.setTotalProfit("20 BEX");
|
|
|
+ order3.setExpireTime(System.currentTimeMillis());
|
|
|
+ order3.setProfitMode("10点结算");
|
|
|
+ order3.setProgressPercent(50);
|
|
|
+
|
|
|
+ list.add(order1);
|
|
|
+ list.add(order2);
|
|
|
+ list.add(order3);
|
|
|
+
|
|
|
+ // 标签筛选逻辑
|
|
|
+ if ("ongoing".equals(query.getTabType())) {
|
|
|
+ list = list.stream().filter(o -> "进行中".equals(o.getOrderStatus())).collect(Collectors.toList());
|
|
|
+ } else if ("redeemed".equals(query.getTabType())) {
|
|
|
+ list = list.stream().filter(o -> "通缩赎回".equals(o.getOrderStatus())).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+ pageData.setRecords(list);
|
|
|
+
|
|
|
+ return R.ok(pageData);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 质押订单详情接口
|
|
|
+ */
|
|
|
+ @GetMapping("/order/detail/{orderId}")
|
|
|
+ public R<StakingOngoingOrderDetailVO> getOrderDetail(@PathVariable("orderId") Long orderId) {
|
|
|
+ StakingOngoingOrderDetailVO vo = new StakingOngoingOrderDetailVO();
|
|
|
+ // 基础信息
|
|
|
+ vo.setProductName("BEX 3个月质押");
|
|
|
+ vo.setOrderNo("STK202605181004150001");
|
|
|
+ vo.setOrderStatus("进行中");
|
|
|
+
|
|
|
+ // 本金&收益
|
|
|
+ vo.setPrincipalNum("1,000 BEX");
|
|
|
+ vo.setTotalProfit("20 BEX");
|
|
|
+ vo.setSettleDayInfo("30 / 90");
|
|
|
+ vo.setRemainDay("60 天");
|
|
|
+
|
|
|
+ // 价格价值
|
|
|
+ vo.setEntryPrice("1.250000 USDT");
|
|
|
+ vo.setInitialValue("1,250.0000 USDT");
|
|
|
+ vo.setShrinkThreshold("800 BEX");
|
|
|
+ vo.setExpireTime(System.currentTimeMillis());
|
|
|
+
|
|
|
+ // 收益进度
|
|
|
+ List<StakingProfitItemVO> profitList = new ArrayList<>();
|
|
|
+ StakingProfitItemVO item1 = new StakingProfitItemVO();
|
|
|
+ item1.setProfitStatus("收益待领取");
|
|
|
+ item1.setProfitDate(System.currentTimeMillis() - 3600000L);
|
|
|
+ item1.setProfitAmount("0.666666 BEX 待领取");
|
|
|
+ item1.setRemark("");
|
|
|
+
|
|
|
+ StakingProfitItemVO item2 = new StakingProfitItemVO();
|
|
|
+ item2.setProfitStatus("收益待领取");
|
|
|
+ item2.setProfitDate(System.currentTimeMillis() - 3600000L);
|
|
|
+ item2.setProfitAmount("0.666666 BEX 待领取");
|
|
|
+ item2.setRemark("");
|
|
|
+
|
|
|
+ StakingProfitItemVO item3 = new StakingProfitItemVO();
|
|
|
+ item3.setProfitStatus("等待 10:00 结算");
|
|
|
+ item3.setProfitDate(null);
|
|
|
+ item3.setProfitAmount("");
|
|
|
+ item3.setRemark("系统每日固定时间结算,失败可补算");
|
|
|
+
|
|
|
+ profitList.add(item1);
|
|
|
+ profitList.add(item2);
|
|
|
+ profitList.add(item3);
|
|
|
+ vo.setProfitList(profitList);
|
|
|
+
|
|
|
+ return R.ok(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通缩赎回订单详情接口
|
|
|
+ */
|
|
|
+ @GetMapping("/redeem/detail/{orderId}")
|
|
|
+ public R<StakingRedeemOrderDetailVO> getRedeemOrderDetail(@PathVariable("orderId") Long orderId) {
|
|
|
+ StakingRedeemOrderDetailVO vo = new StakingRedeemOrderDetailVO();
|
|
|
+
|
|
|
+ // 状态信息
|
|
|
+ vo.setStatusDesc("通缩赎回已完成");
|
|
|
+ vo.setStatusTip("返还本金已到账,收益已计入待领取,销毁数量已记录");
|
|
|
+
|
|
|
+ // 核心结果
|
|
|
+ vo.setReturnPrincipal("1,000 BEX");
|
|
|
+ vo.setBurnAmount("1,000 BEX");
|
|
|
+
|
|
|
+ // 清算计算
|
|
|
+ vo.setOriginalPrincipal("2,000 BEX");
|
|
|
+ vo.setTotalProfit("1,600 BEX");
|
|
|
+ vo.setEntryPrice("1.000000 USDT");
|
|
|
+ vo.setExpirePrice("2.000000 USDT");
|
|
|
+ vo.setRedeemFormula("min(P, V0 / Pt)");
|
|
|
+ vo.setBurnTxHash("0x8f0b7f3e");
|
|
|
+
|
|
|
+ // 提示文案
|
|
|
+ vo.setProfitTip("收益1,600 BEX归用户所有,已计入待领取;本次通缩只影响本金返还与销毁数量。");
|
|
|
+
|
|
|
+ return R.ok(vo);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 领取收益
|
|
|
+ */
|
|
|
+ @GetMapping("/profit/claim")
|
|
|
+ public R<Boolean> claimProfit() {
|
|
|
+ return R.ok(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 确认质押
|
|
|
+ */
|
|
|
+ @GetMapping("/stake/confirm")
|
|
|
+ public R<Boolean> confirmStake() {
|
|
|
+ return R.ok(true);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|