2
0

9 Commits

Author SHA1 Message Date
caiyuchao
4ed514a806 Merge branch 'main' of http://192.168.2.166:3180/WFC/be.wfc into feature/multi-packages 2025-03-21 10:55:59 +08:00
caiyuchao
42fb1c3d7a feat: 可用套餐数量 2025-03-14 17:04:17 +08:00
caiyuchao
16dc1360ef fix: 可用套餐状态 2025-03-14 12:02:22 +08:00
caiyuchao
f586059272 fix: cdr历史 2025-03-14 12:01:55 +08:00
caiyuchao
3d7c2cb156 fix: 可用套餐 2025-03-14 10:58:57 +08:00
caiyuchao
4c059f6a27 fix: 多套餐查看 2025-03-13 18:18:39 +08:00
caiyuchao
9087a0cf93 feat: 多套餐查看 2025-03-13 18:03:16 +08:00
caiyuchao
675171c15f feat: 购买多套餐 2025-03-13 17:34:06 +08:00
caiyuchao
287c4a3b0f feat: 多套餐开启 2025-03-13 11:51:48 +08:00
11 changed files with 191 additions and 37 deletions

View File

@@ -24,10 +24,10 @@ import java.util.List;
* </p>
*
* @author sys
* @since 2025-02-10
* @since 2025-03-13
*/
@RestController
@RequestMapping("/user/uAccountPackage")
@RequestMapping("/accountPackage")
public class UAccountPackageController extends BaseController {
@Autowired
@@ -36,13 +36,13 @@ public class UAccountPackageController extends BaseController {
@GetMapping("/page")
public TableDataInfo page(UAccountPackage uAccountPackage) {
startPage();
List<UAccountPackage> list = uAccountPackageService.list();
List<UAccountPackage> list = uAccountPackageService.queryList(uAccountPackage);
return getDataTable(list);
}
@GetMapping("/list")
public AjaxResult list(UAccountPackage uAccountPackage) {
List<UAccountPackage> list = uAccountPackageService.list();
List<UAccountPackage> list = uAccountPackageService.queryList(uAccountPackage);
return success(list);
}

View File

@@ -1,5 +1,6 @@
package org.wfc.user.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
@@ -84,4 +85,8 @@ public class UAccountPackage extends BaseData {
@Schema(description = "上行限速启用")
private Boolean upLimitEnable;
@Schema(description = "上行限速启用")
@TableField(exist = false)
private Integer status;
}

View File

@@ -0,0 +1,20 @@
package org.wfc.user.domain.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @description: 套餐状态
* @author: cyc
* @since: 2025-03-14
*/
@Getter
@AllArgsConstructor
public enum PackageStatusEnum {
INVALID(0, "未生效"),
VALID(1, "生效");
private final Integer code;
private final String desc;
}

View File

@@ -0,0 +1,18 @@
package org.wfc.user.domain.convert;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import org.wfc.user.domain.UAccount;
import org.wfc.user.domain.UAccountPackage;
/**
* @description: AccountPackageConvert
* @author: cyc
* @since: 2025-03-14
*/
@Mapper
public interface AccountPackageConvert {
AccountPackageConvert INSTANCE = Mappers.getMapper(AccountPackageConvert.class);
UAccountPackage toAccountPackage(UAccount account);
}

View File

@@ -67,4 +67,6 @@ public class UAccountDashboardVo {
private Long activity;
private Integer status;
private Integer packageNum;
}

View File

@@ -3,14 +3,17 @@ package org.wfc.user.service;
import org.wfc.user.domain.UAccountPackage;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
* 用户平台-账户套餐表 服务类
* </p>
*
* @author sys
* @since 2025-02-10
* @since 2025-03-13
*/
public interface IUAccountPackageService extends IService<UAccountPackage> {
List<UAccountPackage> queryList(UAccountPackage uAccountPackage);
}

View File

@@ -1,10 +1,28 @@
package org.wfc.user.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.wfc.common.mybatis.domain.BaseData;
import org.wfc.common.security.utils.SecurityUtils;
import org.wfc.user.domain.UAccount;
import org.wfc.user.domain.UAccountPackage;
import org.wfc.user.domain.constant.PackageStatusEnum;
import org.wfc.user.domain.convert.AccountPackageConvert;
import org.wfc.user.mapper.UAccountMapper;
import org.wfc.user.mapper.UAccountPackageMapper;
import org.wfc.user.service.IUAccountPackageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.wfc.user.util.AccountUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
@@ -12,9 +30,58 @@ import org.springframework.stereotype.Service;
* </p>
*
* @author sys
* @since 2025-02-10
* @since 2025-03-13
*/
@Service
public class UAccountPackageServiceImpl extends ServiceImpl<UAccountPackageMapper, UAccountPackage> implements IUAccountPackageService {
@Autowired
private UAccountMapper accountMapper;
@Override
public List<UAccountPackage> queryList(UAccountPackage uAccountPackage) {
UAccount account = accountMapper.selectOne(Wrappers.<UAccount>lambdaQuery().eq(UAccount::getUserId, SecurityUtils.getLoginUser().getUserid()), false);
if (ObjectUtil.isNull(account) || !AccountUtil.isPackageValid(account, new Date())) {
return Collections.emptyList();
}
List<UAccountPackage> packages = new ArrayList<>();
// 添加当前生效的
UAccountPackage accountPackage = AccountPackageConvert.INSTANCE.toAccountPackage(account);
accountPackage.setAccountId(account.getId());
accountPackage.setStatus(PackageStatusEnum.VALID.getCode());
packages.add(accountPackage);
uAccountPackage.setAccountId(account.getId());
List<UAccountPackage> invalidPackages = this.list(buildQueryWrapper(uAccountPackage));
invalidPackages = invalidPackages.stream().peek(p -> p.setStatus(PackageStatusEnum.INVALID.getCode()))
.collect(Collectors.toList());
packages.addAll(invalidPackages);
return packages;
}
private LambdaQueryWrapper<UAccountPackage> buildQueryWrapper(UAccountPackage bo) {
LambdaQueryWrapper<UAccountPackage> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getAccountId() != null, UAccountPackage::getAccountId, bo.getAccountId());
lqw.eq(bo.getPackageId() != null, UAccountPackage::getPackageId, bo.getPackageId());
lqw.eq(bo.getTraffic() != null, UAccountPackage::getTraffic, bo.getTraffic());
lqw.eq(bo.getDuration() != null, UAccountPackage::getDuration, bo.getDuration());
lqw.eq(bo.getClientNum() != null, UAccountPackage::getClientNum, bo.getClientNum());
lqw.eq(bo.getExpiredTime() != null, UAccountPackage::getExpiredTime, bo.getExpiredTime());
lqw.like(StrUtil.isNotBlank(bo.getPackageName()), UAccountPackage::getPackageName, bo.getPackageName());
lqw.eq(bo.getPeriodNum() != null, UAccountPackage::getPeriodNum, bo.getPeriodNum());
lqw.eq(bo.getPeriodType() != null, UAccountPackage::getPeriodType, bo.getPeriodType());
lqw.eq(bo.getPrice() != null, UAccountPackage::getPrice, bo.getPrice());
lqw.like(StrUtil.isNotBlank(bo.getRemark()), UAccountPackage::getRemark, bo.getRemark());
lqw.eq(bo.getRateLimitEnable() != null, UAccountPackage::getRateLimitEnable, bo.getRateLimitEnable());
lqw.eq(bo.getTrafficEnable() != null, UAccountPackage::getTrafficEnable, bo.getTrafficEnable());
lqw.eq(bo.getDurationEnable() != null, UAccountPackage::getDurationEnable, bo.getDurationEnable());
lqw.eq(bo.getClientNumEnable() != null, UAccountPackage::getClientNumEnable, bo.getClientNumEnable());
lqw.like(StrUtil.isNotBlank(bo.getRateLimitName()), UAccountPackage::getRateLimitName, bo.getRateLimitName());
lqw.eq(bo.getDownLimit() != null, UAccountPackage::getDownLimit, bo.getDownLimit());
lqw.eq(bo.getDownLimitEnable() != null, UAccountPackage::getDownLimitEnable, bo.getDownLimitEnable());
lqw.eq(bo.getUpLimit() != null, UAccountPackage::getUpLimit, bo.getUpLimit());
lqw.eq(bo.getUpLimitEnable() != null, UAccountPackage::getUpLimitEnable, bo.getUpLimitEnable());
lqw.orderByAsc(BaseData::getCreateTime);
return lqw;
}
}

View File

@@ -1,6 +1,7 @@
package org.wfc.user.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -26,6 +27,7 @@ import org.wfc.user.api.domain.bo.UClientBo;
import org.wfc.user.api.omada.domain.convert.OmadaConvert;
import org.wfc.user.api.omada.domain.dto.ClientRateLimitSettingDto;
import org.wfc.user.domain.UAccount;
import org.wfc.user.domain.UAccountPackage;
import org.wfc.user.domain.UBill;
import org.wfc.user.domain.UBillRule;
import org.wfc.user.domain.UClient;
@@ -39,6 +41,7 @@ import org.wfc.user.mapper.UBillMapper;
import org.wfc.user.mapper.UBillRuleMapper;
import org.wfc.user.mapper.UCdrMapper;
import org.wfc.user.mapper.UClientMapper;
import org.wfc.user.service.IUAccountPackageService;
import org.wfc.user.service.IUAccountService;
import org.wfc.user.service.IUClientService;
import org.wfc.user.util.AccountUtil;
@@ -88,6 +91,9 @@ public class UAccountServiceImpl extends ServiceImpl<UAccountMapper, UAccount> i
@Lazy
private IUClientService uClientService;
@Autowired
private IUAccountPackageService accountPackageService;
@Transactional(rollbackFor = Exception.class)
public void statAndCancelAuthUser() {
// 定时任务查询所有未过期或刚过期(失效时间+定时任务间隔时间)的账户套餐,套餐过期/流量用完/时长用完则取消授权
@@ -163,6 +169,30 @@ public class UAccountServiceImpl extends ServiceImpl<UAccountMapper, UAccount> i
continue;
}
UAccount account = this.getOne(Wrappers.<UAccount>lambdaQuery().eq(UAccount::getUserId, loginClient.getUserId()), false);
// 套餐失效,但是还有其他可用套餐
if (!AccountUtil.isPackageValid(account, current)) {
List<UAccountPackage> accountPackages = accountPackageService.list(Wrappers.<UAccountPackage>lambdaQuery()
.eq(UAccountPackage::getAccountId, account.getId()).orderByAsc(UAccountPackage::getCreateTime));
Optional<UAccountPackage> accountPackageOptional = accountPackages.stream().findFirst();
if (accountPackageOptional.isPresent()) {
wifiApi.reconnectClient(site.getSiteId(), client.getMac());
UAccountPackage accountPackage = accountPackageOptional.get();
Long accountId = account.getId();
BeanUtils.copyProperties(accountPackage, account);
account.setId(accountId);
account.setTrafficUsed(0L);
account.setDurationUsed(0L);
account.setClientNumUsed(0);
Date startTime = new Date();
DateTime endTime = AccountUtil.getEndTime(accountPackage.getPeriodType(), accountPackage.getPeriodNum(), startTime);
account.setStartTime(current);
account.setEndTime(endTime);
// 更新账号套餐和删除使用套餐
this.updateById(account);
accountPackageService.removeById(accountPackage.getId());
}
}
// 套餐失效但是有余额且没有已使用余额reconnect
if (AccountUtil.isPackageUnValidBalanceValid(account, current)) {
wifiApi.reconnectClient(site.getSiteId(), client.getMac());
@@ -254,8 +284,10 @@ public class UAccountServiceImpl extends ServiceImpl<UAccountMapper, UAccount> i
} else {
dashboardVo.setStatus(0);
}
}
List<UAccountPackage> accountPackages = accountPackageService.queryList(new UAccountPackage());
dashboardVo.setPackageNum(accountPackages.size());
return dashboardVo;
}

View File

@@ -135,6 +135,9 @@ public class UCdrServiceImpl extends ServiceImpl<UCdrMapper, UCdr> implements IU
// 新增cdr历史
for (UClient client : allClients) {
if (!Objects.equals(client.getSiteId(), site.getSiteId())) {
continue;
}
UCdr uCdr = this.getOne(Wrappers.<UCdr>lambdaQuery().eq(UCdr::getUserId, client.getUserId())
.eq(UCdr::getClientId, client.getId()), false);
if (ObjectUtil.isNotNull(uCdr)) {
@@ -286,6 +289,7 @@ public class UCdrServiceImpl extends ServiceImpl<UCdrMapper, UCdr> implements IU
userId = hasClient.getUserId();
}
UClient uClient = UClient.builder().clientMac(client.getMac())
.siteId(siteId)
.userId(userId)
.clientName(client.getName())
.clientDeviceType(client.getDeviceType())

View File

@@ -1,8 +1,6 @@
package org.wfc.user.service.impl;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -26,7 +24,6 @@ import org.wfc.user.domain.UPackage;
import org.wfc.user.domain.URateLimit;
import org.wfc.user.domain.constant.OrderStatusEnum;
import org.wfc.user.domain.constant.OrderTypeEnum;
import org.wfc.user.domain.constant.PeriodTypeEnum;
import org.wfc.user.mapper.UAccountPackageMapper;
import org.wfc.user.mapper.UBillMapper;
import org.wfc.user.mapper.UBillRuleMapper;
@@ -111,11 +108,11 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
} else {
accountId = account.getId();
oldBalance = account.getBalance();
isValid = AccountUtil.isValid(account, new Date());
isValid = AccountUtil.isPackageValid(account, new Date());
}
if (OrderTypeEnum.PACKAGE.getCode().equals(order.getType())) {
// 套餐
callbackPackage(order, account, false);
callbackPackage(order, account, isValid);
} else if (OrderTypeEnum.RECHARGE.getCode().equals(order.getType())) {
// 充值
// 更新账户余额
@@ -138,7 +135,7 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
wifiApi.authClient(client.getSiteId(), client.getClientMac());
// 套餐生效已授权时调reconnect重连接口以便截取时间
if (isValid && !(OrderTypeEnum.RECHARGE.getCode().equals(order.getType()) && oldBalance.compareTo(BigDecimal.ZERO) > 0)) {
wifiApi.reconnectClient(client.getSiteId(), client.getClientMac());
// wifiApi.reconnectClient(client.getSiteId(), client.getClientMac());
}
// 带宽限速
ClientRateLimitSettingDto clientRateLimitSetting = OmadaConvert.INSTANCE.toClientRateLimitSettingDto(account);
@@ -197,6 +194,9 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
if (isValid) {
BeanUtils.copyProperties(uPackage, accountPackage);
accountPackage.setId(null);
accountPackage.setCreateTime(null);
accountPackage.setAccountId(account.getId());
accountPackage.setPackageId(order.getPackageId());
accountPackageMapper.insert(accountPackage);
} else {
@@ -206,33 +206,12 @@ public class UOrderServiceImpl extends ServiceImpl<UOrderMapper, UOrder> impleme
account.setDurationUsed(0L);
account.setClientNumUsed(0);
Date current = new Date();
DateTime endTime = getEndTime(uPackage, current);
DateTime endTime = AccountUtil.getEndTime(uPackage.getPeriodType(), uPackage.getPeriodNum(), current);
account.setStartTime(current);
account.setEndTime(endTime);
}
}
private static DateTime getEndTime(UPackage uPackage, Date current) {
DateTime endTime = null;
// 计算有效时间
switch (PeriodTypeEnum.getByCode(uPackage.getPeriodType())) {
case HOUR:
endTime = DateUtil.offset(current, DateField.HOUR, uPackage.getPeriodNum());
break;
case DAY:
endTime = DateUtil.offset(current, DateField.DAY_OF_YEAR, uPackage.getPeriodNum());
break;
case MONTH:
endTime = DateUtil.offset(current, DateField.MONTH, uPackage.getPeriodNum());
break;
case YEAR:
endTime = DateUtil.offset(current, DateField.YEAR, uPackage.getPeriodNum());
break;
default:
}
return endTime;
}
@Override
public Long saveOrder(UOrder order) {
order.setUserId(SecurityUtils.getUserId());

View File

@@ -1,8 +1,11 @@
package org.wfc.user.util;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import org.wfc.user.domain.UAccount;
import org.wfc.user.domain.constant.PeriodTypeEnum;
import java.math.BigDecimal;
import java.util.Date;
@@ -69,4 +72,25 @@ public class AccountUtil {
&& (!account.getDurationEnable() || account.getDurationUsed() <= account.getDuration()))
&& (ObjectUtil.isNull(account.getBalanceUsed()) || account.getBalanceUsed().compareTo(BigDecimal.ZERO) == 0);
}
public static DateTime getEndTime(Integer periodType, Integer periodNum, Date current) {
DateTime endTime = null;
// 计算有效时间
switch (PeriodTypeEnum.getByCode(periodType)) {
case HOUR:
endTime = DateUtil.offset(current, DateField.HOUR, periodNum);
break;
case DAY:
endTime = DateUtil.offset(current, DateField.DAY_OF_YEAR, periodNum);
break;
case MONTH:
endTime = DateUtil.offset(current, DateField.MONTH, periodNum);
break;
case YEAR:
endTime = DateUtil.offset(current, DateField.YEAR, periodNum);
break;
default:
}
return endTime;
}
}