This commit is contained in:
sion
2026-04-08 01:09:57 +08:00
parent 007915b6f2
commit 26169accff
11 changed files with 776 additions and 81 deletions

View File

@@ -254,6 +254,25 @@ public class AdminController {
return Result.success(data);
}
/**
* 用户统计数据(管理后台详情面板)
*/
@GetMapping("/user/stats")
public Result<Map<String, Object>> getUserStats(@RequestParam Long userId) {
if (!UserContext.isSuperAdmin()) {
return Result.fail("无权限访问");
}
User user = userService.getById(userId);
if (user == null) {
return Result.fail("用户不存在");
}
Map<String, Object> stats = assetService.getUserStats(userId);
stats.put("user", user);
return Result.success(stats);
}
/**
* 禁用/启用用户
*/

View File

@@ -5,11 +5,15 @@ import com.it.rattan.monisuo.entity.AccountFlow;
import com.it.rattan.monisuo.entity.AccountFund;
import com.it.rattan.monisuo.entity.AccountTrade;
import com.it.rattan.monisuo.entity.Coin;
import com.it.rattan.monisuo.entity.OrderFund;
import com.it.rattan.monisuo.entity.OrderTrade;
import com.it.rattan.monisuo.entity.User;
import com.it.rattan.monisuo.mapper.AccountFlowMapper;
import com.it.rattan.monisuo.mapper.AccountFundMapper;
import com.it.rattan.monisuo.mapper.AccountTradeMapper;
import com.it.rattan.monisuo.mapper.OrderFundMapper;
import com.it.rattan.monisuo.mapper.OrderTradeMapper;
import com.it.rattan.monisuo.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.it.rattan.monisuo.util.OrderNoUtil;
import org.springframework.beans.factory.annotation.Autowired;
@@ -44,6 +48,12 @@ public class AssetService {
@Autowired
private AccountFlowMapper accountFlowMapper;
@Autowired
private OrderFundMapper orderFundMapper;
@Autowired
private UserMapper userMapper;
@Autowired
private CoinService coinService;
@@ -379,4 +389,142 @@ public class AssetService {
result.put("totalProfit", totalProfit);
return result;
}
/**
* 获取用户统计数据(管理后台用)
*/
public Map<String, Object> getUserStats(Long userId) {
Map<String, Object> result = new HashMap<>();
// 1. 资金账户
AccountFund fund = getOrCreateFundAccount(userId);
Map<String, Object> fundAccount = new HashMap<>();
fundAccount.put("balance", fund.getBalance());
fundAccount.put("frozen", fund.getFrozen());
fundAccount.put("totalDeposit", fund.getTotalDeposit());
fundAccount.put("totalWithdraw", fund.getTotalWithdraw());
result.put("fundAccount", fundAccount);
// 2. 交易账户持仓
result.put("tradeAccounts", getTradeAccount(userId));
// 3. 充提统计(一次查询按类型分组,避免两次查询)
LambdaQueryWrapper<OrderFund> fundOrderWrapper = new LambdaQueryWrapper<>();
fundOrderWrapper.eq(OrderFund::getUserId, userId);
List<OrderFund> allFundOrders = orderFundMapper.selectList(fundOrderWrapper);
List<OrderFund> allDeposits = allFundOrders.stream()
.filter(o -> o.getType() == 1).collect(Collectors.toList());
List<OrderFund> allWithdraws = allFundOrders.stream()
.filter(o -> o.getType() == 2).collect(Collectors.toList());
Map<String, Object> depositStats = new HashMap<>();
depositStats.put("totalCount", allDeposits.size());
depositStats.put("totalAmount", allDeposits.stream().map(OrderFund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
depositStats.put("successCount", allDeposits.stream().filter(o -> o.getStatus() == 3).count());
depositStats.put("successAmount", allDeposits.stream().filter(o -> o.getStatus() == 3).map(OrderFund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
result.put("depositStats", depositStats);
Map<String, Object> withdrawStats = new HashMap<>();
withdrawStats.put("totalCount", allWithdraws.size());
withdrawStats.put("totalAmount", allWithdraws.stream().map(OrderFund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
withdrawStats.put("successCount", allWithdraws.stream().filter(o -> o.getStatus() == 2).count());
withdrawStats.put("successAmount", allWithdraws.stream().filter(o -> o.getStatus() == 2).map(OrderFund::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
withdrawStats.put("totalFee", allWithdraws.stream().filter(o -> o.getStatus() == 2).map(o -> o.getFee() != null ? o.getFee() : BigDecimal.ZERO).reduce(BigDecimal.ZERO, BigDecimal::add));
result.put("withdrawStats", withdrawStats);
// 5. 推广统计(优化:批量查询消除 N+1
// 直接推广人referredBy = userId
LambdaQueryWrapper<User> referralWrapper = new LambdaQueryWrapper<>();
referralWrapper.eq(User::getReferredBy, userId)
.orderByDesc(User::getCreateTime);
List<User> directReferrals = userMapper.selectList(referralWrapper);
List<Long> directIds = directReferrals.stream().map(User::getId).collect(Collectors.toList());
// 间接推广人:一次 IN 查询
long indirectCount = 0;
if (!directIds.isEmpty()) {
LambdaQueryWrapper<User> indirectWrapper = new LambdaQueryWrapper<>();
indirectWrapper.in(User::getReferredBy, directIds);
indirectCount = userMapper.selectCount(indirectWrapper);
}
// 批量查询直接推广人是否已充值(一次 IN 查询)
Set<Long> depositedUserIds = new HashSet<>();
if (!directIds.isEmpty()) {
LambdaQueryWrapper<OrderFund> batchDepositWrapper = new LambdaQueryWrapper<>();
batchDepositWrapper.in(OrderFund::getUserId, directIds)
.eq(OrderFund::getType, 1).eq(OrderFund::getStatus, 3)
.select(OrderFund::getUserId)
.groupBy(OrderFund::getUserId);
orderFundMapper.selectList(batchDepositWrapper)
.forEach(o -> depositedUserIds.add(o.getUserId()));
}
List<Map<String, Object>> referralList = new ArrayList<>();
for (User ref : directReferrals) {
Map<String, Object> refInfo = new HashMap<>();
refInfo.put("userId", ref.getId());
refInfo.put("username", ref.getUsername());
refInfo.put("nickname", ref.getNickname());
refInfo.put("createTime", ref.getCreateTime());
refInfo.put("deposited", depositedUserIds.contains(ref.getId()));
referralList.add(refInfo);
}
Map<String, Object> referralStats = new HashMap<>();
referralStats.put("directCount", directReferrals.size());
referralStats.put("indirectCount", indirectCount);
referralStats.put("referrals", referralList);
result.put("referralStats", referralStats);
// 6. 福利统计(从 account_flow 查询福利类型记录)
LambdaQueryWrapper<AccountFlow> bonusWrapper = new LambdaQueryWrapper<>();
bonusWrapper.eq(AccountFlow::getUserId, userId)
.eq(AccountFlow::getFlowType, 7)
.orderByDesc(AccountFlow::getCreateTime);
List<AccountFlow> bonusFlows = accountFlowMapper.selectList(bonusWrapper);
BigDecimal totalBonusClaimed = bonusFlows.stream()
.map(AccountFlow::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
List<Map<String, Object>> bonusRecords = new ArrayList<>();
for (AccountFlow flow : bonusFlows) {
Map<String, Object> record = new HashMap<>();
String remark = flow.getRemark() != null ? flow.getRemark() : "福利";
String type;
if (remark.startsWith("新人首充")) {
type = "新人首充福利";
} else if (remark.startsWith("间接推广")) {
type = "间接推广奖励";
} else if (remark.startsWith("邀请奖励")) {
type = "直接推广奖励";
} else {
type = remark;
}
record.put("type", type);
record.put("amount", flow.getAmount());
record.put("time", flow.getCreateTime());
bonusRecords.add(record);
}
Map<String, Object> bonusStats = new HashMap<>();
bonusStats.put("totalBonusClaimed", totalBonusClaimed);
bonusStats.put("totalBonusCount", bonusFlows.size());
bonusStats.put("records", bonusRecords);
result.put("bonusStats", bonusStats);
// 7. 最近充提订单最近20笔
LambdaQueryWrapper<OrderFund> recentOrderWrapper = new LambdaQueryWrapper<>();
recentOrderWrapper.eq(OrderFund::getUserId, userId)
.orderByDesc(OrderFund::getCreateTime)
.last("LIMIT 20");
result.put("recentFundOrders", orderFundMapper.selectList(recentOrderWrapper));
// 8. 最近交易订单最近20笔
LambdaQueryWrapper<OrderTrade> recentTradeWrapper = new LambdaQueryWrapper<>();
recentTradeWrapper.eq(OrderTrade::getUserId, userId)
.orderByDesc(OrderTrade::getCreateTime)
.last("LIMIT 20");
result.put("recentTradeOrders", orderTradeMapper.selectList(recentTradeWrapper));
return result;
}
}