Merge branch 'dev/dev_xp' into dev/dev

This commit is contained in:
2025-08-20 16:41:14 +08:00
7 changed files with 872 additions and 79 deletions

View File

@@ -2160,13 +2160,13 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
@Override
public Boolean addSubAccount(AddSubAccountDTO addSubAccountDTO) {
AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder();
Account account = accountMapper.selectById(authPrincipalVo.getId());
int subUserRole = getSubUserRole(account.getSystemUser());
Account adminAcc = accountMapper.selectById(authPrincipalVo.getId());
int subUserRole = getSubUserRole(adminAcc.getSystemUser());
if (addSubAccountDTO.getId() == null) {
return createSubAccount(addSubAccountDTO, account, subUserRole, addSubAccountDTO.getCreditsUsageLimit(), null);
return createSubAccount(addSubAccountDTO, adminAcc, subUserRole);
} else {
return updateSubAccount(addSubAccountDTO, account, subUserRole);
return updateSubAccount(addSubAccountDTO, adminAcc, subUserRole);
}
}
@@ -2182,135 +2182,184 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
}
@Transactional(rollbackFor = Exception.class)
public Boolean createSubAccount(AddSubAccountDTO addSubAccountDTO, Account account, int subUserRole,
BigDecimal creditsLimit, BigDecimal creditsUsage) {
public Boolean createSubAccount(AddSubAccountDTO addSubAccountDTO, Account adminAcc, int subUserRole) {
QueryWrapper<Account> qw = new QueryWrapper<>();
qw.lambda().eq(Account::getOrganizationName, account.getOrganizationName());
qw.lambda().eq(Account::getOrganizationName, adminAcc.getOrganizationName());
List<Account> accounts = accountMapper.selectList(qw);
// 校验子账号总数是否达上限
if (account.getSubAccountNum() == null || account.getSubAccountNum() <= 0){
if (adminAcc.getSubAccountNum() == null || adminAcc.getSubAccountNum() <= 0){
throw new BusinessException("Error: Sub-account quota reached (Max: 0). Upgrade to create more.");
}
if (accounts.size() >= account.getSubAccountNum()) {
throw new BusinessException("Error: Sub-account quota reached (Max: " + account.getSubAccountNum() + "). Upgrade to create more.");
if (accounts.size() >= adminAcc.getSubAccountNum()) {
throw new BusinessException("Error: Sub-account quota reached (Max: " + adminAcc.getSubAccountNum() + "). Upgrade to create more.");
}
if (StringUtil.isNullOrEmpty(addSubAccountDTO.getUserEmail())){
throw new BusinessException("email.cannot.be.empty");
}
if (StringUtil.isNullOrEmpty(addSubAccountDTO.getUserPassword())){
throw new BusinessException("password.cannot.be.empty");
}
// 校验邮箱是否已加入组织
if (isUserEmailExists(account.getOrganizationName(), addSubAccountDTO.getUserEmail())) {
if (isUserEmailExists(adminAcc.getOrganizationName(), addSubAccountDTO.getUserEmail())) {
throw new BusinessException("This organization already has an account with the same email.", ResultEnum.PROMPT.getCode());
}
// 校验用户名是否同名
if (isUsernameExists(account.getOrganizationName(), addSubAccountDTO.getUserName())) {
if (isUsernameExists(adminAcc.getOrganizationName(), addSubAccountDTO.getUserName())) {
throw new BusinessException("This organization already has an account with the same username.");
}
// 之后是否需要检验密码不能设置为空
// 校验当前账号邮箱是否有个人账号
Account subAccount = accountMapper.selectOne(new QueryWrapper<Account>().eq("user_email", addSubAccountDTO.getUserEmail()));
List<Integer> personAccRole = Arrays.asList(0, 1, 2, 3);
List<Integer> orgAccRole = Arrays.asList(5, 6, 7, 8);
BigDecimal remainingCredits = adminRemainingCredits(adminAcc);
// 将个人账号加入组织
if (Objects.nonNull(subAccount) && personAccRole.contains(subAccount.getSystemUser())) {
log.info("将用户{} 加入组织{}", addSubAccountDTO.getUserEmail(), account.getOrganizationName());
log.info("将用户{} 加入组织{}", addSubAccountDTO.getUserEmail(), adminAcc.getOrganizationName());
subAccount.setUserName(addSubAccountDTO.getUserName());
subAccount.setUserPassword(addSubAccountDTO.getUserPassword());
subAccount.setSystemUser(subUserRole);
subAccount.setOrganizationName(account.getOrganizationName());
subAccount.setParentId(account.getId());
if (Objects.nonNull(creditsLimit)){
subAccount.setCreditsUsageLimit(creditsLimit);
subAccount.setCreditsUsage(creditsUsage);
if (Objects.nonNull(subAccount.getCredits())) {
subAccount.setCredits(subAccount.getCreditsUsageLimit().add(subAccount.getCredits()));
subAccount.setOrganizationName(adminAcc.getOrganizationName());
subAccount.setParentId(adminAcc.getId());
if (Objects.nonNull(subAccount.getCreditsUsageLimit())){
if (remainingCredits.compareTo(subAccount.getCreditsUsageLimit()) < 0) {
throw new BusinessException("Insufficient credits (Balance: " + remainingCredits + ").", ResultEnum.PROMPT.getCode());
}
}else {
handleSubAccCredits(subAccount, account);
}
subAccount.setUpdateDate(new Date());
updateById(subAccount);
updateById(account);
} else if (Objects.nonNull(subAccount) && orgAccRole.contains(subAccount.getSystemUser())) {
throw new BusinessException("邮箱 " + addSubAccountDTO.getUserEmail() + " 已加入其他组织", ResultEnum.PROMPT.getCode());
} else {
subAccount = new Account();
subAccount.setUserName(addSubAccountDTO.getUserName());
subAccount.setUserEmail(addSubAccountDTO.getUserEmail());
subAccount.setUserPassword(addSubAccountDTO.getUserPassword());
if (Objects.nonNull(creditsLimit)){
subAccount.setCreditsUsageLimit(creditsLimit);
subAccount.setCreditsUsage(creditsUsage);
subAccount.setCreditsUsageLimit(subAccount.getCreditsUsageLimit());
subAccount.setCreditsUsage(subAccount.getCreditsUsageLimit());
if (Objects.nonNull(subAccount.getCredits())) {
subAccount.setCredits(subAccount.getCreditsUsageLimit().add(subAccount.getCredits()));
}else {
subAccount.setCredits(subAccount.getCreditsUsageLimit());
}
} else {
handleSubAccCredits(subAccount, account);
updateById(account);
adminAcc.setCreditsUsage(adminAcc.getCreditsUsage().add(subAccount.getCreditsUsageLimit()));
adminAcc.setCredits(adminAcc.getCreditsUsageLimit().subtract(adminAcc.getCreditsUsage()));
adminAcc.setUpdateDate(new Date());
}else {
handleSubAccCredits(subAccount, adminAcc);
}
subAccount.setUpdateDate(new Date());
updateById(subAccount);
updateById(adminAcc);
}
// 输入的账号已存在于其他组织
else if (Objects.nonNull(subAccount) && orgAccRole.contains(subAccount.getSystemUser())) {
throw new BusinessException("邮箱 " + addSubAccountDTO.getUserEmail() + " 已加入其他组织", ResultEnum.PROMPT.getCode());
}
// 完全新建一个账号
else {
subAccount = new Account();
subAccount.setUserName(addSubAccountDTO.getUserName());
subAccount.setUserEmail(addSubAccountDTO.getUserEmail());
subAccount.setUserPassword(addSubAccountDTO.getUserPassword());
// 指定积分上限
if (Objects.nonNull(addSubAccountDTO.getCreditsUsageLimit())){
if (remainingCredits.compareTo(addSubAccountDTO.getCreditsUsageLimit()) < 0) {
throw new BusinessException("Insufficient credits (Balance: " + remainingCredits + ").", ResultEnum.PROMPT.getCode());
}
subAccount.setCreditsUsageLimit(addSubAccountDTO.getCreditsUsageLimit());
subAccount.setCreditsUsage(Objects.isNull(addSubAccountDTO.getCreditsUsage()) ? BigDecimal.ZERO : addSubAccountDTO.getCreditsUsage());
if (Objects.nonNull(subAccount.getCredits())) {
subAccount.setCredits(subAccount.getCreditsUsageLimit().add(subAccount.getCredits()));
}else {
subAccount.setCredits(subAccount.getCreditsUsageLimit());
}
adminAcc.setCreditsUsage(adminAcc.getCreditsUsage().add(subAccount.getCreditsUsageLimit()));
adminAcc.setCredits(adminAcc.getCreditsUsageLimit().subtract(adminAcc.getCreditsUsage()));
adminAcc.setUpdateDate(new Date());
}
// 未指定积分使用上限
else {
handleSubAccCredits(subAccount, adminAcc);
updateById(adminAcc);
}
subAccount.setSystemUser(subUserRole);
subAccount.setLanguage(Language.ENGLISH.name());
subAccount.setCreateDate(new Date());
subAccount.setIsTrial(0);
subAccount.setIsBeginner(1);
subAccount.setParentId(account.getId());
subAccount.setOrganizationName(account.getOrganizationName());
subAccount.setParentId(adminAcc.getId());
subAccount.setOrganizationName(adminAcc.getOrganizationName());
accountMapper.insert(subAccount);
}
return Boolean.TRUE;
}
private Boolean updateSubAccount(AddSubAccountDTO addSubAccountDTO, Account account, int subUserRole) {
private Boolean updateSubAccount(AddSubAccountDTO addSubAccountDTO, Account adminAcc, int subUserRole) {
Account exAccountInfo = baseMapper.selectById(addSubAccountDTO.getId());
// 校验用户名是否同名
if (!exAccountInfo.getUserName().equals(addSubAccountDTO.getUserName()) && isUsernameExists(account.getOrganizationName(), addSubAccountDTO.getUserName())) {
if (!StringUtil.isNullOrEmpty(addSubAccountDTO.getUserName())
&& !exAccountInfo.getUserName().equals(addSubAccountDTO.getUserName())
&& isUsernameExists(adminAcc.getOrganizationName(), addSubAccountDTO.getUserName())) {
throw new BusinessException("This organization already has an account with the same username.");
}else if (!exAccountInfo.getUserName().equals(addSubAccountDTO.getUserName())){
}else if (!StringUtil.isNullOrEmpty(addSubAccountDTO.getUserName())
&& !exAccountInfo.getUserName().equals(addSubAccountDTO.getUserName())){
exAccountInfo.setUserName(addSubAccountDTO.getUserName());
}
// 判断积分变更是增加还是减少还是没变化
if (Objects.nonNull(addSubAccountDTO.getCreditsUsageLimit()) && exAccountInfo.getCreditsUsageLimit().compareTo(addSubAccountDTO.getCreditsUsageLimit()) < 0) {
BigDecimal remainingCredits = adminRemainingCredits(account);
// 判断积分变更是增加还是减少还是没变化需修改子账号的credits\creditsUsageLimit,管理员账号的creditUsage
if (Objects.nonNull(addSubAccountDTO.getCreditsUsageLimit())
&& exAccountInfo.getCreditsUsageLimit().compareTo(addSubAccountDTO.getCreditsUsageLimit()) < 0) {
BigDecimal remainingCredits = adminRemainingCredits(adminAcc);
// 新增加的积分
BigDecimal addedCredits = addSubAccountDTO.getCreditsUsageLimit().subtract(exAccountInfo.getCreditsUsageLimit());
if (remainingCredits.compareTo(addedCredits) >= 0) {
// 更新管理员已分配的积分
account.setCreditsUsage(account.getCreditsUsage().add(addedCredits));
// 更新子账号的积分上限
adminAcc.setCreditsUsage(adminAcc.getCreditsUsage().add(addedCredits));
adminAcc.setCredits(adminAcc.getCreditsUsageLimit().subtract(adminAcc.getCreditsUsage()));
// 更新子账号的积分上限和目前所有积分总数
exAccountInfo.setCreditsUsageLimit(addSubAccountDTO.getCreditsUsageLimit());
exAccountInfo.setCredits(exAccountInfo.getCredits().add(addedCredits));
} else {
throw new BusinessException("Insufficient credits (Balance: " + remainingCredits + ").", ResultEnum.PROMPT.getCode());
}
} else if (Objects.nonNull(addSubAccountDTO.getCreditsUsageLimit()) && exAccountInfo.getCreditsUsageLimit().compareTo(addSubAccountDTO.getCreditsUsageLimit()) > 0) {
} else if (Objects.nonNull(addSubAccountDTO.getCreditsUsageLimit())
&& exAccountInfo.getCreditsUsageLimit().compareTo(addSubAccountDTO.getCreditsUsageLimit()) > 0) {
if (exAccountInfo.getCreditsUsage().compareTo(addSubAccountDTO.getCreditsUsageLimit()) > 0) {
throw new BusinessException("Usage alert: " + exAccountInfo.getCreditsUsage() + " credits consumed this month. New limit must be ≥ " + exAccountInfo.getCreditsUsage() + " .");
} else {
// 减少的积分
BigDecimal subtractedCredits = exAccountInfo.getCreditsUsageLimit().subtract(addSubAccountDTO.getCreditsUsageLimit());
// 更新管理员已分配的积分(积分回流)
account.setCreditsUsage(account.getCreditsUsage().subtract(subtractedCredits));
// 更新子账号的积分上限
adminAcc.setCreditsUsage(adminAcc.getCreditsUsage().subtract(subtractedCredits));
adminAcc.setCredits(adminAcc.getCreditsUsageLimit().subtract(adminAcc.getCreditsUsage()));
// 更新子账号的积分上限和目前所有积分总数
exAccountInfo.setCreditsUsageLimit(addSubAccountDTO.getCreditsUsageLimit());
exAccountInfo.setCredits(exAccountInfo.getCredits().subtract(subtractedCredits));
}
}
// 校验密码是否变更
if (!StringUtil.isNullOrEmpty(addSubAccountDTO.getUserPassword())
&& !exAccountInfo.getUserPassword().equals(addSubAccountDTO.getUserPassword())){
exAccountInfo.setUserPassword(addSubAccountDTO.getUserPassword());
}
// 校验邮箱是否变更
if (!exAccountInfo.getUserEmail().equals(addSubAccountDTO.getUserEmail())) {
if (!StringUtil.isNullOrEmpty(addSubAccountDTO.getUserEmail())
&& !exAccountInfo.getUserEmail().equals(addSubAccountDTO.getUserEmail())) {
// 原账号的积分使用上限
BigDecimal creditsLimit = exAccountInfo.getCreditsUsageLimit();
// BigDecimal creditsLimit = exAccountInfo.getCreditsUsageLimit();
addSubAccountDTO.setCreditsUsageLimit(exAccountInfo.getCreditsUsageLimit());
// 原账号已使用的积分
BigDecimal creditsUsage = exAccountInfo.getCreditsUsage();
// BigDecimal creditsUsage = exAccountInfo.getCreditsUsage();
addSubAccountDTO.setCreditsUsage(exAccountInfo.getCreditsUsage());
// 这里移除原账号,但是积分不回流,机构分配的积分会由下一个账号继续持有(包括积分上限和已使用的积分都保持不变)
removeSubAccount(new AddSubAccountDTO(Collections.singletonList(addSubAccountDTO.getId())), false);
// 移入新子账号(可能是移入,也可能是新增)
createSubAccount(addSubAccountDTO, account, subUserRole, creditsLimit, creditsUsage);
createSubAccount(addSubAccountDTO, adminAcc, subUserRole);
} else {
baseMapper.updateById(exAccountInfo);
baseMapper.updateById(account);
baseMapper.updateById(adminAcc);
}
return Boolean.TRUE;
}
@@ -2364,6 +2413,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
subAcc.setCreditsUsageLimit(BigDecimal.ZERO);
}
adminAcc.setCreditsUsage(adminAcc.getCreditsUsage().add(subAcc.getCreditsUsageLimit()));
adminAcc.setCredits(adminAcc.getCreditsUsageLimit().subtract(adminAcc.getCreditsUsage()));
adminAcc.setUpdateDate(new Date());
log.debug("分配积分: subAccId={}, defaultCredits={}, remainingCredits={}", subAcc.getId(), defaultCredits, remainingCredits);
@@ -2426,7 +2476,8 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
}
// 是否需要将积分回流
if (returnCredits && unusedCreditsTotal.compareTo(BigDecimal.ZERO) != 0){
adminAcc.setCreditsUsage(adminAcc.getCreditsUsage().subtract(unusedCreditsTotal));
BigDecimal subtracted = adminAcc.getCreditsUsage().subtract(unusedCreditsTotal);
adminAcc.setCreditsUsage(subtracted.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : subtracted);
adminAcc.setUpdateDate(new Date());
baseMapper.updateById(adminAcc);
}
@@ -2462,12 +2513,17 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
if (StringUtils.isNotBlank(subAccountPageDTO.getEndTime())) {
qw.lambda().le(Account::getCreateDate, subAccountPageDTO.getEndTime());
}
if (StringUtils.isNotBlank(subAccountPageDTO.getEmail())) {
qw.lambda().like(Account::getUserEmail, subAccountPageDTO.getEmail());
if (subAccountPageDTO.getEmail() != null && subAccountPageDTO.getEmail().size() == 1){
qw.lambda().like(Account::getUserEmail, subAccountPageDTO.getEmail().get(0));
}else if (subAccountPageDTO.getEmail() != null && subAccountPageDTO.getEmail().size() > 1){
qw.lambda().in(Account::getUserEmail, subAccountPageDTO.getEmail());
}
if (StringUtils.isNotBlank(subAccountPageDTO.getUserName())) {
qw.lambda().like(Account::getUserName, subAccountPageDTO.getUserName());
if (subAccountPageDTO.getUserName() != null && subAccountPageDTO.getUserName().size() == 1){
qw.lambda().like(Account::getUserName, subAccountPageDTO.getUserName().get(0));
}else if (subAccountPageDTO.getUserName() != null && subAccountPageDTO.getUserName().size() > 1){
qw.lambda().in(Account::getUserName, subAccountPageDTO.getUserName());
}
// 执行分页查询
IPage<Account> page = accountMapper.selectPage(new Page<>(subAccountPageDTO.getPage(), subAccountPageDTO.getSize()), qw);

View File

@@ -7,6 +7,7 @@ import com.ai.da.common.response.PageBaseResponse;
import com.ai.da.common.response.ResultEnum;
import com.ai.da.common.utils.CopyUtil;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.common.utils.RedisUtilEnhance;
import com.ai.da.common.utils.SendEmailUtil;
import com.ai.da.mapper.primary.*;
import com.ai.da.mapper.primary.entity.*;
@@ -298,6 +299,9 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
return redisUtil.getAffiliateLinkViewCount(affiliateId);
}
@Resource
private RedisUtilEnhance redisUtilEnhance;
public void syncLinkViewCountToDB() {
// 1、获取当前所有激活状态的affiliate
List<Affiliate> affiliateList = baseMapper.selectList(new QueryWrapper<Affiliate>().lambda().eq(Affiliate::getStatus, "Active"));
@@ -307,7 +311,7 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
String redisKey = AFFILIATE_LINK_VIEW_KEY + affiliate.getId();
// 原子性获取并重置为0
Long redisCount = redisUtil.getAndSetKey(redisKey, 0L);
Long redisCount = redisUtilEnhance.getAndSetKey(redisKey, 0L);
if (redisCount != null && redisCount > 0) {
// 累加到数据库