chore: initialize qiming workspace repository
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>app-platform-subscription</artifactId>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>app-platform-subscription-api</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-application</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.xspaceagi.subscription.api.rpc;
|
||||
|
||||
import com.xspaceagi.subscription.app.service.SubscriptionPlanAppService;
|
||||
import com.xspaceagi.subscription.app.service.UserSubscriptionAppService;
|
||||
import com.xspaceagi.subscription.sdk.dto.*;
|
||||
import com.xspaceagi.subscription.sdk.rpc.ISubscriptionRpcService;
|
||||
import com.xspaceagi.system.spec.common.RequestContext;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SubscriptionRpcService implements ISubscriptionRpcService {
|
||||
|
||||
@Resource
|
||||
private UserSubscriptionAppService userSubscriptionAppService;
|
||||
|
||||
@Resource
|
||||
private SubscriptionPlanAppService subscriptionPlanAppService;
|
||||
|
||||
@Override
|
||||
public List<UserSubscriptionDTO> getUserSubscriptions(SubscriptionQueryRequest request) {
|
||||
Assert.notNull(request, "参数不能为空");
|
||||
Assert.notNull(request.getUserId(), "用户ID不能为空");
|
||||
Assert.notNull(request.getTenantId(), "租户ID不能为空");
|
||||
if (RequestContext.get() == null) {
|
||||
RequestContext.setThreadTenantId(request.getTenantId());
|
||||
try {
|
||||
return userSubscriptionAppService.getUserSubscriptions(request);
|
||||
} finally {
|
||||
RequestContext.remove();
|
||||
}
|
||||
}
|
||||
return userSubscriptionAppService.getUserSubscriptions(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserSubscriptionDTO getUserCurrentSystemSubscription(Long userId) {
|
||||
return userSubscriptionAppService.getUserCurrentSystemSubscription(userId, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserSubscriptionDTO createSubscription(CreateSubscriptionRequest request) {
|
||||
Assert.notNull(request, "参数不能为空");
|
||||
Assert.notNull(request.getUserId(), "用户ID不能为空");
|
||||
Assert.notNull(request.getTenantId(), "租户ID不能为空");
|
||||
Assert.notNull(request.getPlanId(), "计划ID不能为空");
|
||||
if (RequestContext.get() == null) {
|
||||
RequestContext.setThreadTenantId(request.getTenantId());
|
||||
try {
|
||||
return userSubscriptionAppService.createSubscription(request);
|
||||
} finally {
|
||||
RequestContext.remove();
|
||||
}
|
||||
}
|
||||
return userSubscriptionAppService.createSubscription(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createPlan(PlanDTO dto) {
|
||||
Assert.notNull(dto, "参数不能为空");
|
||||
Assert.notNull(dto.getBizType(), "业务类型不能为空");
|
||||
return subscriptionPlanAppService.createPlan(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updatePlan(PlanDTO dto) {
|
||||
Assert.notNull(dto, "参数不能为空");
|
||||
Assert.notNull(dto.getId(), "计划ID不能为空");
|
||||
return subscriptionPlanAppService.updatePlan(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offlinePlan(Long tenantId, Long planId) {
|
||||
Assert.notNull(planId, "计划ID不能为空");
|
||||
return subscriptionPlanAppService.offlinePlan(planId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlanDTO getPlan(Long planId) {
|
||||
return subscriptionPlanAppService.getPlanById(planId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PlanDTO> listPlans(PlanQueryRequest request) {
|
||||
Assert.notNull(request, "参数不能为空");
|
||||
return subscriptionPlanAppService.listPlans(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int incrementCallCount(Long tenantId, Long subscriptionId, Integer count) {
|
||||
Assert.notNull(subscriptionId, "订阅ID不能为空");
|
||||
if (RequestContext.get() == null) {
|
||||
RequestContext.setThreadTenantId(tenantId);
|
||||
try {
|
||||
return userSubscriptionAppService.incrementCallCount(subscriptionId, count);
|
||||
} finally {
|
||||
RequestContext.remove();
|
||||
}
|
||||
}
|
||||
return userSubscriptionAppService.incrementCallCount(subscriptionId, count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>app-platform-subscription</artifactId>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>app-platform-subscription-application</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-domain</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-infra</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-credit-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-tx</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.xspaceagi.subscription.app.service;
|
||||
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanDTO;
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanQueryRequest;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SubscriptionPlanAppService {
|
||||
|
||||
Long createPlan(PlanDTO dto);
|
||||
|
||||
boolean updatePlan(PlanDTO dto);
|
||||
|
||||
boolean offlinePlan(Long id);
|
||||
|
||||
boolean deletePlan(Long id);
|
||||
|
||||
PlanDTO getPlanById(Long id);
|
||||
|
||||
PlanDTO getPlanById(Long id, boolean showPlanDescItems);
|
||||
|
||||
List<PlanDTO> listPlans(PlanQueryRequest query);
|
||||
|
||||
PlanDTO getFreePlan(BizTypeEnum bizType, String bizId, boolean showPlanDescItems);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.xspaceagi.subscription.app.service;
|
||||
|
||||
import com.xspaceagi.subscription.sdk.dto.*;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface UserSubscriptionAppService {
|
||||
|
||||
List<UserSubscriptionDTO> getUserSubscriptions(SubscriptionQueryRequest query);
|
||||
|
||||
/**
|
||||
* 获取用户当前指定业务(智能体)订阅
|
||||
*/
|
||||
UserSubscriptionDTO getUserCurrentSubscription(Long userId, BizTypeEnum bizType, String bizId);
|
||||
|
||||
/**
|
||||
* 获取用户当前系统订阅
|
||||
*/
|
||||
UserSubscriptionDTO getUserCurrentSystemSubscription(Long userId, boolean showPlanDescItems);
|
||||
|
||||
UserSubscriptionDTO createSubscription(CreateSubscriptionRequest request);
|
||||
|
||||
SubscriptionStatsDTO getSubscriptionStats(SubscriptionStatsQueryRequest request);
|
||||
|
||||
void reset(UserSubscriptionDTO subscriptionDTO);
|
||||
|
||||
int incrementCallCount(Long subscriptionId, Integer count);
|
||||
|
||||
List<UserSubscriptionDTO> getNeedResetSubscriptions();
|
||||
|
||||
List<UserSubscriptionDTO> getExpiredSubscriptions();
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package com.xspaceagi.subscription.app.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.xspaceagi.agent.core.sdk.IAgentRpcService;
|
||||
import com.xspaceagi.agent.core.sdk.IModelRpcService;
|
||||
import com.xspaceagi.agent.core.sdk.dto.AgentInfoDto;
|
||||
import com.xspaceagi.agent.core.sdk.dto.ModelInfoDto;
|
||||
import com.xspaceagi.knowledge.sdk.response.KnowledgeConfigVo;
|
||||
import com.xspaceagi.knowledge.sdk.sevice.IKnowledgeConfigRpcService;
|
||||
import com.xspaceagi.subscription.app.service.SubscriptionPlanAppService;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.Plan;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.UserSubscription;
|
||||
import com.xspaceagi.subscription.infra.dao.mapper.PlanMapper;
|
||||
import com.xspaceagi.subscription.infra.dao.mapper.UserSubscriptionMapper;
|
||||
import com.xspaceagi.subscription.infra.dao.service.IPlanService;
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanDTO;
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanItemGroupDTO;
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanQueryRequest;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import com.xspaceagi.subscription.spec.enums.PlanPeriodEnum;
|
||||
import com.xspaceagi.subscription.spec.enums.PlanStatusEnum;
|
||||
import com.xspaceagi.system.sdk.permission.IPermissionCacheRpcSerivce;
|
||||
import com.xspaceagi.system.sdk.permission.IUserDataPermissionRpcService;
|
||||
import com.xspaceagi.system.sdk.service.dto.MergedGroupDataPermissionDto;
|
||||
import com.xspaceagi.system.spec.enums.ErrorCodeEnum;
|
||||
import com.xspaceagi.system.spec.exception.BizException;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SubscriptionPlanAppServiceImpl implements SubscriptionPlanAppService {
|
||||
|
||||
@Resource
|
||||
private IPlanService planService;
|
||||
|
||||
@Resource
|
||||
private PlanMapper planMapper;
|
||||
|
||||
@Resource
|
||||
private UserSubscriptionMapper userSubscriptionMapper;
|
||||
|
||||
@Resource
|
||||
private IUserDataPermissionRpcService iUserDataPermissionRpcService;
|
||||
|
||||
@Resource
|
||||
private IModelRpcService iModelRpcService;
|
||||
|
||||
@Resource
|
||||
private IAgentRpcService iAgentRpcService;
|
||||
|
||||
@Resource
|
||||
private IKnowledgeConfigRpcService iKnowledgeConfigRpcService;
|
||||
|
||||
@Resource
|
||||
private IPermissionCacheRpcSerivce iPermissionCacheRpcSerivce;
|
||||
|
||||
@Override
|
||||
public Long createPlan(PlanDTO dto) {
|
||||
if (dto.getName() == null || dto.getName().isBlank()) {
|
||||
throw new BizException(ErrorCodeEnum.INVALID_PARAM.getCode(), "计划名称不能为空");
|
||||
}
|
||||
if (dto.getBizType() == null) {
|
||||
throw new BizException(ErrorCodeEnum.INVALID_PARAM.getCode(), "业务类型不能为空");
|
||||
}
|
||||
if (!BizTypeEnum.SYSTEM.equals(dto.getBizType()) && (dto.getBizId() == null || dto.getBizId().isBlank())) {
|
||||
throw new BizException(ErrorCodeEnum.INVALID_PARAM.getCode(), "非系统业务类型必须指定业务对象ID");
|
||||
}
|
||||
|
||||
Plan entity = convertToEntity(dto);
|
||||
if (entity.getStatus() == null) {
|
||||
entity.setStatus(PlanStatusEnum.ONLINE.getCode());
|
||||
}
|
||||
if (entity.getIsHot() == null) {
|
||||
entity.setIsHot(false);
|
||||
}
|
||||
if (entity.getCreditAmount() == null) {
|
||||
entity.setCreditAmount(java.math.BigDecimal.ZERO);
|
||||
}
|
||||
if (entity.getCallLimitCount() == null) {
|
||||
entity.setCallLimitCount(-1);
|
||||
}
|
||||
if (entity.getFunctionOnly() == null) {
|
||||
entity.setFunctionOnly(false);
|
||||
}
|
||||
planService.save(entity);
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updatePlan(PlanDTO dto) {
|
||||
if (dto.getId() == null) {
|
||||
throw new BizException(ErrorCodeEnum.INVALID_PARAM.getCode(), "计划ID不能为空");
|
||||
}
|
||||
PlanDTO oldDto = getPlanById(dto.getId());
|
||||
Plan entity = convertToEntity(dto);
|
||||
try {
|
||||
return planService.updateById(entity);
|
||||
} finally {
|
||||
if (oldDto != null && dto.getGroupIds() != null) {
|
||||
iPermissionCacheRpcSerivce.clearCacheAllByTenant(oldDto.getTenantId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offlinePlan(Long id) {
|
||||
Plan entity = new Plan();
|
||||
entity.setId(id);
|
||||
entity.setStatus(PlanStatusEnum.OFFLINE.getCode());
|
||||
return planService.updateById(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deletePlan(Long id) {
|
||||
Long count = userSubscriptionMapper.selectCount(
|
||||
new LambdaQueryWrapper<UserSubscription>()
|
||||
.eq(UserSubscription::getPlanId, id));
|
||||
if (count != null && count > 0) {
|
||||
throw new BizException("PLAN_HAS_SUBSCRIPTION", "该计划已有用户订阅,无法删除");
|
||||
}
|
||||
return planService.removeById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlanDTO getPlanById(Long id) {
|
||||
Plan entity = planService.getById(id);
|
||||
return entity != null ? convertToDTO(entity, true) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlanDTO getPlanById(Long id, boolean showPlanDescItems) {
|
||||
Plan entity = planService.getById(id);
|
||||
return entity != null ? convertToDTO(entity, showPlanDescItems) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PlanDTO> listPlans(PlanQueryRequest query) {
|
||||
List<Plan> plans = planMapper.selectListWithFilters(query);
|
||||
return plans.stream().map((Plan entity) -> convertToDTO(entity, true)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlanDTO getFreePlan(BizTypeEnum bizType, String bizId, boolean showPlanDescItems) {
|
||||
Plan freePlan = planService.lambdaQuery()
|
||||
.eq(Plan::getBizType, bizType.getCode())
|
||||
.eq(bizType != BizTypeEnum.SYSTEM, Plan::getBizId, bizId)
|
||||
.eq(Plan::getStatus, PlanStatusEnum.ONLINE.getCode())
|
||||
.eq(Plan::getPrice, BigDecimal.ZERO)
|
||||
.orderByAsc(Plan::getSort)
|
||||
.orderByAsc(Plan::getId)
|
||||
.last("LIMIT 1")
|
||||
.one();
|
||||
return convertToDTO(freePlan, showPlanDescItems);
|
||||
}
|
||||
|
||||
private Plan convertToEntity(PlanDTO dto) {
|
||||
Plan entity = new Plan();
|
||||
BeanUtils.copyProperties(dto, entity);
|
||||
if (dto.getBizType() != null) {
|
||||
entity.setBizType(dto.getBizType().getCode());
|
||||
}
|
||||
|
||||
entity.setPeriod(dto.getPeriod() != null ? dto.getPeriod().getCode() : PlanPeriodEnum.FOREVER.getCode());
|
||||
if (dto.getExtra() != null) {
|
||||
entity.setExtra(JSON.toJSONString(dto.getExtra()));
|
||||
}
|
||||
if (dto.getGroupIds() != null) {
|
||||
entity.setGroupIds(JSON.toJSONString(dto.getGroupIds()));
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private PlanDTO convertToDTO(Plan entity, boolean showPlanDescItems) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
PlanDTO dto = new PlanDTO();
|
||||
BeanUtils.copyProperties(entity, dto);
|
||||
dto.setBizType(BizTypeEnum.fromCode(entity.getBizType()));
|
||||
dto.setPeriod(PlanPeriodEnum.getByCode(entity.getPeriod()));
|
||||
|
||||
List<PlanItemGroupDTO> itemGroups = new ArrayList<>();
|
||||
PlanItemGroupDTO itemGroup = new PlanItemGroupDTO();
|
||||
itemGroups.add(itemGroup);
|
||||
itemGroup.setName("基础权限");
|
||||
itemGroup.setDescription("基础权限");
|
||||
itemGroup.setGroupType(PlanItemGroupDTO.GroupType.BASE);
|
||||
itemGroup.setItems(new ArrayList<>());
|
||||
if (dto.getBizType() == BizTypeEnum.SYSTEM) {
|
||||
dto.setItemGroups(itemGroups);
|
||||
}
|
||||
try {
|
||||
if (entity.getExtra() != null) {
|
||||
dto.setExtra(JSON.parseObject(entity.getExtra()));
|
||||
}
|
||||
if (entity.getGroupIds() != null) {
|
||||
dto.setGroupIds(JSON.parseArray(entity.getGroupIds(), Long.class));
|
||||
if (CollectionUtils.isNotEmpty(dto.getGroupIds()) && showPlanDescItems) {
|
||||
MergedGroupDataPermissionDto mergedGroupDataPermission = iUserDataPermissionRpcService.getMergedGroupDataPermission(dto.getGroupIds());
|
||||
if (mergedGroupDataPermission != null) {
|
||||
itemGroup.getItems().add(new PlanItemGroupDTO.ItemDTO("工作空间", "可创建工作空间数量 " + (mergedGroupDataPermission.getMaxSpaceCount() == null || mergedGroupDataPermission.getMaxSpaceCount() < 0 ? "无限制" : mergedGroupDataPermission.getMaxSpaceCount()), "workspace", mergedGroupDataPermission.getMaxSpaceCount() != null && mergedGroupDataPermission.getMaxSpaceCount() != 0));
|
||||
itemGroup.getItems().add(new PlanItemGroupDTO.ItemDTO("智能体", "可创建智能体数量 " + (mergedGroupDataPermission.getMaxAgentCount() == null || mergedGroupDataPermission.getMaxAgentCount() < 0 ? "无限制" : mergedGroupDataPermission.getMaxAgentCount()), "agent", mergedGroupDataPermission.getMaxAgentCount() != null && mergedGroupDataPermission.getMaxAgentCount() != 0));
|
||||
itemGroup.getItems().add(new PlanItemGroupDTO.ItemDTO("网页应用", "可创建网页应用数量 " + (mergedGroupDataPermission.getMaxPageAppCount() == null || mergedGroupDataPermission.getMaxPageAppCount() < 0 ? "无限制" : mergedGroupDataPermission.getMaxPageAppCount()), "pageApp", mergedGroupDataPermission.getMaxPageAppCount() != null && mergedGroupDataPermission.getMaxPageAppCount() != 0));
|
||||
itemGroup.getItems().add(new PlanItemGroupDTO.ItemDTO("知识库", "可创建知识库数量 " + (mergedGroupDataPermission.getMaxKnowledgeCount() == null || mergedGroupDataPermission.getMaxKnowledgeCount() < 0 ? "无限制" : mergedGroupDataPermission.getMaxKnowledgeCount()), "kb", mergedGroupDataPermission.getMaxKnowledgeCount() != null && mergedGroupDataPermission.getMaxKnowledgeCount() != 0));
|
||||
itemGroup.getItems().add(new PlanItemGroupDTO.ItemDTO("知识库", "知识库存储空间上限 " + (mergedGroupDataPermission.getKnowledgeStorageLimitGb() == null || mergedGroupDataPermission.getKnowledgeStorageLimitGb().doubleValue() < 0 ? "无限制" : mergedGroupDataPermission.getKnowledgeStorageLimitGb() + " GB"), "kb", mergedGroupDataPermission.getKnowledgeStorageLimitGb() != null && mergedGroupDataPermission.getKnowledgeStorageLimitGb().doubleValue() != 0));
|
||||
itemGroup.getItems().add(new PlanItemGroupDTO.ItemDTO("数据表", "可创建数据表数量 " + (mergedGroupDataPermission.getMaxDataTableCount() == null || mergedGroupDataPermission.getMaxDataTableCount() < 0 ? "无限制" : mergedGroupDataPermission.getMaxDataTableCount()), "table", mergedGroupDataPermission.getKnowledgeStorageLimitGb() != null && mergedGroupDataPermission.getKnowledgeStorageLimitGb().doubleValue() != 0));
|
||||
itemGroup.getItems().add(new PlanItemGroupDTO.ItemDTO("定时任务", "可创建定时任务数量 " + (mergedGroupDataPermission.getMaxScheduledTaskCount() == null || mergedGroupDataPermission.getMaxScheduledTaskCount() < 0 ? "无限制" : mergedGroupDataPermission.getMaxScheduledTaskCount()), "task", mergedGroupDataPermission.getMaxScheduledTaskCount() != null && mergedGroupDataPermission.getMaxScheduledTaskCount() != 0));
|
||||
itemGroup.getItems().add(new PlanItemGroupDTO.ItemDTO("智能体电脑", "个人智能体电脑内存 " + (mergedGroupDataPermission.getAgentComputerMemoryGb() == null || mergedGroupDataPermission.getAgentComputerMemoryGb().doubleValue() < 0 ? "无限制" : mergedGroupDataPermission.getAgentComputerMemoryGb() + " GB"), "agentComputer", mergedGroupDataPermission.getAgentComputerMemoryGb() != null && mergedGroupDataPermission.getAgentComputerMemoryGb() != 0));
|
||||
|
||||
//模型权限
|
||||
List<ModelInfoDto> modelInfoList = iModelRpcService.getModelInfoList(mergedGroupDataPermission.getModelIds());
|
||||
if (CollectionUtils.isNotEmpty(modelInfoList)) {
|
||||
itemGroup = new PlanItemGroupDTO();
|
||||
itemGroups.add(itemGroup);
|
||||
itemGroup.setName("模型权限");
|
||||
itemGroup.setDescription("模型权限");
|
||||
itemGroup.setGroupType(PlanItemGroupDTO.GroupType.MODEL);
|
||||
itemGroup.setItems(modelInfoList.stream().map(modelInfo -> new PlanItemGroupDTO.ItemDTO(modelInfo.getName(), modelInfo.getDescription(), modelInfo.getIcon(), true)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
//智能体权限
|
||||
List<AgentInfoDto> agentInfoList = iAgentRpcService.queryAgentInfoList(mergedGroupDataPermission.getAgentIds()).getData();
|
||||
if (CollectionUtils.isNotEmpty(agentInfoList)) {
|
||||
itemGroup = new PlanItemGroupDTO();
|
||||
itemGroups.add(itemGroup);
|
||||
itemGroup.setName("智能体权限");
|
||||
itemGroup.setDescription("智能体权限");
|
||||
itemGroup.setGroupType(PlanItemGroupDTO.GroupType.AGENT);
|
||||
itemGroup.setItems(agentInfoList.stream().map(agentInfo -> new PlanItemGroupDTO.ItemDTO(agentInfo.getName(), agentInfo.getDescription(), agentInfo.getIcon(), true)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
//网页应用权限
|
||||
List<AgentInfoDto> pageAgentInfoList = iAgentRpcService.queryAgentInfoList(mergedGroupDataPermission.getPageAgentIds()).getData();
|
||||
if (CollectionUtils.isNotEmpty(pageAgentInfoList)) {
|
||||
itemGroup = new PlanItemGroupDTO();
|
||||
itemGroups.add(itemGroup);
|
||||
itemGroup.setName("网页应用权限");
|
||||
itemGroup.setDescription("网页应用权限");
|
||||
itemGroup.setGroupType(PlanItemGroupDTO.GroupType.APP);
|
||||
itemGroup.setItems(pageAgentInfoList.stream().map(agentInfo -> new PlanItemGroupDTO.ItemDTO(agentInfo.getName(), agentInfo.getDescription(), agentInfo.getIcon(), true)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
//知识库权限
|
||||
List<KnowledgeConfigVo> knowledgeInfoList = iKnowledgeConfigRpcService.listByIds(mergedGroupDataPermission.getKnowledgeIds());
|
||||
if (CollectionUtils.isNotEmpty(knowledgeInfoList)) {
|
||||
itemGroup = new PlanItemGroupDTO();
|
||||
itemGroups.add(itemGroup);
|
||||
itemGroup.setName("知识库权限");
|
||||
itemGroup.setDescription("知识库权限");
|
||||
itemGroup.setGroupType(PlanItemGroupDTO.GroupType.KB);
|
||||
itemGroup.setItems(knowledgeInfoList.stream().map(knowledgeInfo -> new PlanItemGroupDTO.ItemDTO(knowledgeInfo.getName(), knowledgeInfo.getDescription(), knowledgeInfo.getIcon(), true)).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
//API权限
|
||||
List<MergedGroupDataPermissionDto.OpenApiConfig> openApiConfigs = mergedGroupDataPermission.getOpenApiConfigs();
|
||||
if (CollectionUtils.isNotEmpty(openApiConfigs)) {
|
||||
itemGroup = new PlanItemGroupDTO();
|
||||
itemGroups.add(itemGroup);
|
||||
itemGroup.setName("API权限");
|
||||
itemGroup.setDescription("API权限");
|
||||
itemGroup.setGroupType(PlanItemGroupDTO.GroupType.API);
|
||||
itemGroup.setOpenApiConfigs(openApiConfigs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.xspaceagi.subscription.app.service.impl;
|
||||
|
||||
import com.xspaceagi.subscription.app.service.UserSubscriptionAppService;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.UserSubscription;
|
||||
import com.xspaceagi.subscription.infra.dao.service.IUserSubscriptionService;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import com.xspaceagi.subscription.spec.enums.SubscriptionStatusEnum;
|
||||
import com.xspaceagi.system.sdk.permission.IPermissionCacheRpcSerivce;
|
||||
import com.xspaceagi.system.sdk.service.AbstractTaskExecuteService;
|
||||
import com.xspaceagi.system.sdk.service.ScheduleTaskApiService;
|
||||
import com.xspaceagi.system.sdk.service.dto.ScheduleTaskDto;
|
||||
import com.xspaceagi.system.spec.common.RequestContext;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service("subscriptionResetTaskService")
|
||||
public class SubscriptionResetTaskServiceImpl extends AbstractTaskExecuteService {
|
||||
|
||||
@Resource
|
||||
private ScheduleTaskApiService scheduleTaskApiService;
|
||||
|
||||
@Resource
|
||||
private UserSubscriptionAppService userSubscriptionAppService;
|
||||
|
||||
@Resource
|
||||
private IUserSubscriptionService userSubscriptionService;
|
||||
|
||||
@Resource
|
||||
private IPermissionCacheRpcSerivce iPermissionCacheRpcSerivce;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
scheduleTaskApiService.start(ScheduleTaskDto.builder()
|
||||
.taskId("subscriptionResetTaskService")
|
||||
.beanId("subscriptionResetTaskService")
|
||||
.maxExecTimes(Long.MAX_VALUE)
|
||||
.cron(ScheduleTaskDto.Cron.EVERY_10_SECOND.getCron())
|
||||
.params(Map.of())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean execute(ScheduleTaskDto scheduleTaskDto) {
|
||||
userSubscriptionAppService.getNeedResetSubscriptions().forEach(subscription -> {
|
||||
try {
|
||||
RequestContext.setThreadTenantId(subscription.getTenantId());
|
||||
userSubscriptionAppService.reset(subscription);
|
||||
} finally {
|
||||
RequestContext.remove();
|
||||
}
|
||||
});
|
||||
userSubscriptionAppService.getExpiredSubscriptions().forEach(subscription -> {
|
||||
try {
|
||||
RequestContext.setThreadTenantId(subscription.getTenantId());
|
||||
UserSubscription update = new UserSubscription();
|
||||
update.setId(subscription.getId());
|
||||
update.setStatus(SubscriptionStatusEnum.EXPIRED.getCode());
|
||||
userSubscriptionService.updateById(update);
|
||||
if (subscription.getBizType() == BizTypeEnum.SYSTEM) {
|
||||
iPermissionCacheRpcSerivce.clearCacheByTenantAndUserIds(subscription.getTenantId(), Collections.singletonList(subscription.getUserId()));
|
||||
log.info("用户订阅已过期,清除用户权限缓存,用户ID:{}", subscription.getUserId());
|
||||
}
|
||||
} finally {
|
||||
RequestContext.remove();
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
package com.xspaceagi.subscription.app.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.xspaceagi.credit.sdk.dto.CreditAddRequest;
|
||||
import com.xspaceagi.credit.sdk.rpc.ICreditRpcService;
|
||||
import com.xspaceagi.credit.spec.enums.CreditTypeEnum;
|
||||
import com.xspaceagi.subscription.app.service.SubscriptionPlanAppService;
|
||||
import com.xspaceagi.subscription.app.service.UserSubscriptionAppService;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.Plan;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.UserSubscription;
|
||||
import com.xspaceagi.subscription.infra.dao.mapper.UserSubscriptionMapper;
|
||||
import com.xspaceagi.subscription.infra.dao.service.IPlanService;
|
||||
import com.xspaceagi.subscription.infra.dao.service.IUserSubscriptionService;
|
||||
import com.xspaceagi.subscription.sdk.dto.*;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import com.xspaceagi.subscription.spec.enums.PlanPeriodEnum;
|
||||
import com.xspaceagi.subscription.spec.enums.SubscriptionStatusEnum;
|
||||
import com.xspaceagi.system.sdk.permission.IPermissionCacheRpcSerivce;
|
||||
import com.xspaceagi.system.sdk.server.IUserRpcService;
|
||||
import com.xspaceagi.system.spec.common.UserContext;
|
||||
import com.xspaceagi.system.spec.exception.BizException;
|
||||
import com.xspaceagi.system.spec.tenant.thread.TenantFunctions;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class UserSubscriptionAppServiceImpl implements UserSubscriptionAppService {
|
||||
|
||||
@Resource
|
||||
private IUserSubscriptionService userSubscriptionService;
|
||||
|
||||
@Resource
|
||||
private UserSubscriptionMapper userSubscriptionMapper;
|
||||
|
||||
@Resource
|
||||
private SubscriptionPlanAppService subscriptionPlanAppService;
|
||||
|
||||
@Resource
|
||||
private IPlanService planService;
|
||||
|
||||
@Resource
|
||||
private ICreditRpcService iCreditRpcService;
|
||||
|
||||
@Resource
|
||||
private IUserRpcService iUserRpcService;
|
||||
|
||||
@Resource
|
||||
private IPermissionCacheRpcSerivce iPermissionCacheRpcSerivce;
|
||||
|
||||
@Override
|
||||
public List<UserSubscriptionDTO> getUserSubscriptions(SubscriptionQueryRequest query) {
|
||||
if (query.getBizType() == null) {
|
||||
query.setBizType(BizTypeEnum.SYSTEM);
|
||||
}
|
||||
List<UserSubscription> subscriptions = userSubscriptionService.lambdaQuery()
|
||||
.eq(UserSubscription::getUserId, query.getUserId())
|
||||
.eq(query.getBizType() != null, UserSubscription::getBizType, query.getBizType())
|
||||
.eq(query.getStatus() != null, UserSubscription::getStatus, SubscriptionStatusEnum.getByCode(query.getStatus()))
|
||||
.eq(query.getBizId() != null, UserSubscription::getBizId, query.getBizId())
|
||||
.list();
|
||||
|
||||
List<UserSubscriptionDTO> result = subscriptions.stream().map((UserSubscription entity) -> convertToDTO(entity, query.isShowPlanDescItems())).collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
//是否包含可用订阅
|
||||
boolean hasActiveSubscription = result.stream().anyMatch(sub -> sub.getPlan() != null && sub.getStatus() == SubscriptionStatusEnum.ACTIVE);
|
||||
boolean shouldAddFreePlan = (BizTypeEnum.SYSTEM.equals(query.getBizType()) && !hasActiveSubscription)
|
||||
|| (!BizTypeEnum.SYSTEM.equals(query.getBizType()) && query.getBizId() != null && !hasActiveSubscription);
|
||||
if (shouldAddFreePlan) {
|
||||
PlanDTO freePlan = subscriptionPlanAppService.getFreePlan(query.getBizType(), query.getBizId(), query.isShowPlanDescItems());
|
||||
if (freePlan != null) {
|
||||
result.add(buildFreePlanDTO(freePlan));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserSubscriptionDTO getUserCurrentSubscription(Long userId, BizTypeEnum bizType, String bizId) {
|
||||
SubscriptionQueryRequest request = new SubscriptionQueryRequest();
|
||||
request.setUserId(userId);
|
||||
request.setBizType(bizType);
|
||||
request.setBizId(bizId);
|
||||
request.setStatus(SubscriptionStatusEnum.ACTIVE.getCode());
|
||||
return getUserSubscriptions(request).stream().findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserSubscriptionDTO getUserCurrentSystemSubscription(Long userId, boolean showPlanDescItems) {
|
||||
SubscriptionQueryRequest request = new SubscriptionQueryRequest();
|
||||
request.setUserId(userId);
|
||||
request.setBizType(BizTypeEnum.SYSTEM);
|
||||
request.setStatus(SubscriptionStatusEnum.ACTIVE.getCode());
|
||||
return getUserSubscriptions(request).stream().findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscriptionStatsDTO getSubscriptionStats(SubscriptionStatsQueryRequest request) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
Date todayStart = cal.getTime();
|
||||
|
||||
cal.set(Calendar.DAY_OF_MONTH, 1);
|
||||
Date monthStart = cal.getTime();
|
||||
|
||||
Map<String, Object> stats = userSubscriptionMapper.selectStatsByPlanBiz(
|
||||
request.getBizType().getCode(), request.getBizId(), todayStart, monthStart);
|
||||
|
||||
SubscriptionStatsDTO dto = new SubscriptionStatsDTO();
|
||||
dto.setTotalCount(toLong(stats.get("totalCount")));
|
||||
dto.setTodayCount(toLong(stats.get("todayCount")));
|
||||
dto.setMonthCount(toLong(stats.get("monthCount")));
|
||||
|
||||
Long total = userSubscriptionMapper.countByPlanBiz(
|
||||
request.getBizType().getCode(), request.getBizId());
|
||||
int offset = (request.getPageNum() - 1) * request.getPageSize();
|
||||
List<UserSubscription> subscribers = userSubscriptionMapper.selectByPlanBiz(
|
||||
request.getBizType().getCode(), request.getBizId(), offset, request.getPageSize());
|
||||
|
||||
dto.setSubscribers(subscribers.stream().map((UserSubscription entity) -> convertToDTO(entity, true)).collect(Collectors.toList()));
|
||||
dto.setTotal(total);
|
||||
dto.setPageNum(request.getPageNum());
|
||||
dto.setPageSize(request.getPageSize());
|
||||
|
||||
//补充用户信息
|
||||
List<Long> userIds = dto.getSubscribers().stream().map(UserSubscriptionDTO::getUserId).toList();
|
||||
List<UserContext> userContexts = iUserRpcService.queryUserListByIds(userIds);
|
||||
Map<Long, UserContext> userContextMap = userContexts.stream().collect(Collectors.toMap(UserContext::getUserId, userContext -> userContext, (a, b) -> a));
|
||||
dto.getSubscribers().forEach(subscriber -> {
|
||||
UserContext userContext = userContextMap.get(subscriber.getUserId());
|
||||
if (userContext != null) {
|
||||
String userName = StringUtils.isNotBlank(userContext.getNickName()) ? userContext.getNickName() : userContext.getUserName();
|
||||
subscriber.setSubscriber(new UserSubscriptionDTO.Subscriber(userContext.getUserId(), userName, userContext.getAvatar()));
|
||||
}
|
||||
});
|
||||
return dto;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public UserSubscriptionDTO createSubscription(CreateSubscriptionRequest request) {
|
||||
Plan plan = planService.getById(request.getPlanId());
|
||||
if (plan == null) {
|
||||
throw new BizException("PLAN_NOT_FOUND", "订阅计划不存在");
|
||||
}
|
||||
if (plan.getStatus() == null || plan.getStatus() == 0) {
|
||||
throw new BizException("PLAN_NOT_AVAILABLE", "订阅计划已下线");
|
||||
}
|
||||
|
||||
UserSubscription existingSub = userSubscriptionMapper.selectByUserIdAndPlanId(
|
||||
request.getUserId(), request.getPlanId());
|
||||
|
||||
if (existingSub == null) {
|
||||
// Check if user has a subscription to a different plan (switch plan)
|
||||
UserSubscription otherSub = userSubscriptionService.lambdaQuery()
|
||||
.eq(UserSubscription::getBizType, plan.getBizType())
|
||||
.eq(!plan.getBizType().equals(BizTypeEnum.SYSTEM.getCode()), UserSubscription::getBizId, plan.getBizId())
|
||||
.eq(UserSubscription::getUserId, request.getUserId())
|
||||
.one();
|
||||
if (otherSub == null) {
|
||||
return handleNewSubscription(request, plan);
|
||||
}
|
||||
existingSub = otherSub;
|
||||
}
|
||||
|
||||
boolean isSamePlan = existingSub.getPlanId().equals(request.getPlanId());
|
||||
existingSub.setExtra(request.getExtraJsonString());
|
||||
if (isSamePlan) {
|
||||
if (request.getExtraJsonString() != null) {
|
||||
existingSub.setPeriod(plan.getPeriod());
|
||||
userSubscriptionService.updateById(existingSub);
|
||||
}
|
||||
if (SubscriptionStatusEnum.ACTIVE.getCode().equals(existingSub.getStatus()) && existingSub.getEndTime() != null
|
||||
&& existingSub.getEndTime().getTime() > System.currentTimeMillis()) {
|
||||
return handleRenewActive(existingSub, plan);
|
||||
} else {
|
||||
return handleRenewExpired(existingSub, plan);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return handleChangePlan(existingSub, plan);
|
||||
} finally {
|
||||
//清除用户权限缓存
|
||||
if (plan.getBizType().equals(BizTypeEnum.SYSTEM.getCode())) {
|
||||
iPermissionCacheRpcSerivce.clearCacheByTenantAndUserIds(plan.getTenantId(), List.of(request.getUserId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private UserSubscriptionDTO handleNewSubscription(CreateSubscriptionRequest request, Plan plan) {
|
||||
Date startTime = new Date();
|
||||
Date endTime = PlanPeriodEnum.FOREVER.getCode().equals(plan.getPeriod()) ? addMonths(startTime, 1200) : addMonths(startTime, plan.getPeriod());
|
||||
UserSubscription sub = UserSubscription.builder()
|
||||
.userId(request.getUserId())
|
||||
.tenantId(plan.getTenantId())
|
||||
.planId(plan.getId())
|
||||
.bizType(BizTypeEnum.valueOf(plan.getBizType()))
|
||||
.bizId(plan.getBizId())
|
||||
.period(plan.getPeriod())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.status(SubscriptionStatusEnum.ACTIVE.getCode())
|
||||
.callUsedCount(0)
|
||||
.nextResetTime(startTime)
|
||||
.extra(request.getExtraJsonString())
|
||||
.build();
|
||||
userSubscriptionService.save(sub);
|
||||
UserSubscriptionDTO userSubscriptionDTO = convertToDTO(sub, false);
|
||||
reset(userSubscriptionDTO);//积分发放
|
||||
log.info("新建订阅, userId={}, planId={}, endTime={}", request.getUserId(), plan.getId(), endTime);
|
||||
return convertToDTO(sub, false);
|
||||
}
|
||||
|
||||
private UserSubscriptionDTO handleRenewActive(UserSubscription sub, Plan plan) {
|
||||
Date newEndTime = PlanPeriodEnum.FOREVER.getCode().equals(plan.getPeriod()) ? addMonths(sub.getEndTime(), 1200) : addMonths(sub.getEndTime(), plan.getPeriod());
|
||||
userSubscriptionMapper.updateEndTime(sub.getId(), newEndTime);
|
||||
sub.setEndTime(newEndTime);
|
||||
|
||||
log.info("续费(生效中), userId={}, planId={}, newEndTime={}", sub.getUserId(), plan.getId(), newEndTime);
|
||||
return convertToDTO(sub, false);
|
||||
}
|
||||
|
||||
private UserSubscriptionDTO handleRenewExpired(UserSubscription sub, Plan plan) {
|
||||
Date startTime = new Date();
|
||||
Date endTime = PlanPeriodEnum.FOREVER.getCode().equals(plan.getPeriod()) ? addMonths(startTime, 1200) : addMonths(startTime, plan.getPeriod());
|
||||
userSubscriptionMapper.updatePeriod(sub.getId(), startTime, endTime,
|
||||
SubscriptionStatusEnum.ACTIVE.getCode());
|
||||
sub.setStartTime(startTime);
|
||||
sub.setEndTime(endTime);
|
||||
sub.setStatus(SubscriptionStatusEnum.ACTIVE.getCode());
|
||||
|
||||
log.info("续费(已过期/已取消), userId={}, planId={}, endTime={}", sub.getUserId(), plan.getId(), endTime);
|
||||
UserSubscriptionDTO userSubscriptionDTO = convertToDTO(sub, false);
|
||||
reset(userSubscriptionDTO);//积分发放
|
||||
return userSubscriptionDTO;
|
||||
}
|
||||
|
||||
//更新计划,降级不退,升级补差价
|
||||
private UserSubscriptionDTO handleChangePlan(UserSubscription oldSub, Plan newPlan) {
|
||||
userSubscriptionMapper.deleteById(oldSub.getId());
|
||||
Date startTime = new Date();
|
||||
Date endTime = PlanPeriodEnum.FOREVER.getCode().equals(newPlan.getPeriod()) ? addMonths(startTime, 1200) : addMonths(startTime, newPlan.getPeriod());
|
||||
UserSubscription sub = UserSubscription.builder()
|
||||
.userId(oldSub.getUserId())
|
||||
.tenantId(newPlan.getTenantId())
|
||||
.planId(newPlan.getId())
|
||||
.bizType(BizTypeEnum.valueOf(newPlan.getBizType()))
|
||||
.bizId(newPlan.getBizId())
|
||||
.period(newPlan.getPeriod())
|
||||
.startTime(startTime)
|
||||
.endTime(endTime)
|
||||
.status(SubscriptionStatusEnum.ACTIVE.getCode())
|
||||
.callUsedCount(0)
|
||||
.nextResetTime(startTime) // 后台任务会执行初始化积分发放以及更新下次重置时间
|
||||
.extra(oldSub.getExtra())
|
||||
.build();
|
||||
userSubscriptionService.save(sub);
|
||||
UserSubscriptionDTO userSubscriptionDTO = convertToDTO(sub, false);
|
||||
reset(userSubscriptionDTO);// 积分发放
|
||||
return userSubscriptionDTO;
|
||||
}
|
||||
|
||||
private UserSubscriptionDTO buildFreePlanDTO(PlanDTO plan) {
|
||||
UserSubscriptionDTO dto = new UserSubscriptionDTO();
|
||||
dto.setId(0L);
|
||||
dto.setTenantId(plan.getTenantId());
|
||||
dto.setPlanId(plan.getId());
|
||||
dto.setPlanName(plan.getName());
|
||||
dto.setBizType(plan.getBizType());
|
||||
dto.setBizId(plan.getBizId());
|
||||
dto.setPeriod(plan.getPeriod());
|
||||
dto.setStartTime(new Date());
|
||||
dto.setEndTime(addMonths(dto.getStartTime(), plan.getPeriod().getCode() == 0 ? 1200 : plan.getPeriod().getCode()));
|
||||
dto.setStatus(SubscriptionStatusEnum.ACTIVE);
|
||||
dto.setPlan(plan);
|
||||
return dto;
|
||||
}
|
||||
|
||||
private Date addMonths(Date from, int months) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(from);
|
||||
cal.add(Calendar.MONTH, months);
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
private Long toLong(Object val) {
|
||||
if (val == null) return 0L;
|
||||
if (val instanceof Long) return (Long) val;
|
||||
if (val instanceof Number) return ((Number) val).longValue();
|
||||
return Long.parseLong(val.toString());
|
||||
}
|
||||
|
||||
private UserSubscriptionDTO convertToDTO(UserSubscription entity, boolean showPlanDescItems) {
|
||||
UserSubscriptionDTO dto = new UserSubscriptionDTO();
|
||||
dto.setId(entity.getId());
|
||||
dto.setUserId(entity.getUserId());
|
||||
dto.setPlanId(entity.getPlanId());
|
||||
dto.setStartTime(entity.getStartTime());
|
||||
dto.setEndTime(entity.getEndTime());
|
||||
dto.setStatus(SubscriptionStatusEnum.getByCode(entity.getStatus()));
|
||||
dto.setCreated(entity.getCreated());
|
||||
dto.setModified(entity.getModified());
|
||||
if (dto.getStatus() == SubscriptionStatusEnum.ACTIVE && entity.getEndTime().getTime() < System.currentTimeMillis()) {
|
||||
dto.setStatus(SubscriptionStatusEnum.EXPIRED);
|
||||
if (entity.getId() != null) {
|
||||
UserSubscription update = new UserSubscription();
|
||||
update.setId(entity.getId());
|
||||
update.setStatus(SubscriptionStatusEnum.EXPIRED.getCode());
|
||||
userSubscriptionService.updateById(update);
|
||||
iPermissionCacheRpcSerivce.clearCacheByTenantAndUserIds(entity.getTenantId(), Collections.singletonList(entity.getUserId()));
|
||||
}
|
||||
}
|
||||
|
||||
dto.setCallUsedCount(entity.getCallUsedCount());
|
||||
dto.setNextResetTime(entity.getNextResetTime());
|
||||
PlanDTO plan = subscriptionPlanAppService.getPlanById(entity.getPlanId(), showPlanDescItems);
|
||||
dto.setPlan(plan);
|
||||
if (dto.getPlan() == null && JSON.isValidObject(entity.getExtra())) {
|
||||
JSONObject jsonObject = JSON.parseObject(entity.getExtra());
|
||||
plan = jsonObject.getObject("plan", PlanDTO.class);
|
||||
dto.setPlan(plan);
|
||||
}
|
||||
dto.setPlanName(dto.getPlan().getName());
|
||||
dto.setPeriod(PlanPeriodEnum.getByCode(entity.getPeriod()));
|
||||
dto.setBizType(entity.getBizType());
|
||||
dto.setBizId(entity.getBizId());
|
||||
dto.setTenantId(entity.getTenantId());
|
||||
return dto;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void reset(UserSubscriptionDTO subscriptionDTO) {
|
||||
if (subscriptionDTO.getEndTime() != null && subscriptionDTO.getEndTime().getTime() < System.currentTimeMillis()) {
|
||||
log.info("用户订阅已过期, userId={}, planId={}", subscriptionDTO.getUserId(), subscriptionDTO.getPlanId());
|
||||
return;
|
||||
}
|
||||
if (subscriptionDTO.getNextResetTime() != null && subscriptionDTO.getNextResetTime().getTime() > System.currentTimeMillis()) {
|
||||
log.info("用户订阅未到重置时间, userId={}, planId={}", subscriptionDTO.getUserId(), subscriptionDTO.getPlanId());
|
||||
return;
|
||||
}
|
||||
log.info("用户订阅重置, userId={}, planId={}", subscriptionDTO.getUserId(), subscriptionDTO.getPlanId());
|
||||
Date nextResetTime = addMonths(subscriptionDTO.getStartTime(), 1);
|
||||
while (nextResetTime.getTime() < System.currentTimeMillis()) {
|
||||
nextResetTime = addMonths(nextResetTime, 1);
|
||||
}
|
||||
if (subscriptionDTO.getBizType() == BizTypeEnum.SYSTEM && subscriptionDTO.getPlan() != null && subscriptionDTO.getPlan().getCreditAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
CreditAddRequest creditAddRequest = new CreditAddRequest();
|
||||
creditAddRequest.setUserId(subscriptionDTO.getUserId());
|
||||
creditAddRequest.setAmount(subscriptionDTO.getPlan().getCreditAmount());
|
||||
creditAddRequest.setCreditType(CreditTypeEnum.SUBSCRIPTION);
|
||||
creditAddRequest.setRemark("订阅积分发放");
|
||||
creditAddRequest.setBizNo("sub" + UUID.randomUUID().toString().replace("-", ""));
|
||||
creditAddRequest.setTenantId(subscriptionDTO.getTenantId());
|
||||
iCreditRpcService.addCredit(creditAddRequest);
|
||||
}
|
||||
userSubscriptionMapper.resetCallCount(subscriptionDTO.getId(), nextResetTime);
|
||||
log.info("用户订阅重置成功, userId={}, planId={}", subscriptionDTO.getUserId(), subscriptionDTO.getPlanId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int incrementCallCount(Long subscriptionId, Integer count) {
|
||||
int actualCount = count != null ? count : 1;
|
||||
userSubscriptionMapper.incrementCallCount(subscriptionId, actualCount);
|
||||
return actualCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserSubscriptionDTO> getNeedResetSubscriptions() {
|
||||
List<UserSubscription> subscriptions = TenantFunctions.callWithIgnoreCheck(() -> userSubscriptionService.lambdaQuery()
|
||||
.in(UserSubscription::getBizType, BizTypeEnum.SYSTEM.getCode(), BizTypeEnum.AGENT.getCode())
|
||||
.le(UserSubscription::getNextResetTime, new Date())
|
||||
.last("limit 1000")
|
||||
.list());
|
||||
|
||||
return TenantFunctions.callWithIgnoreCheck(() -> subscriptions.stream().map((UserSubscription entity) -> convertToDTO(entity, false)).collect(Collectors.toCollection(ArrayList::new)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserSubscriptionDTO> getExpiredSubscriptions() {
|
||||
List<UserSubscription> subscriptions = TenantFunctions.callWithIgnoreCheck(() -> userSubscriptionService.lambdaQuery()
|
||||
.ne(UserSubscription::getStatus, SubscriptionStatusEnum.EXPIRED.getCode())
|
||||
.le(UserSubscription::getEndTime, new Date())
|
||||
.last("limit 1000")
|
||||
.list());
|
||||
return TenantFunctions.callWithIgnoreCheck(() -> subscriptions.stream().map((UserSubscription entity) -> convertToDTO(entity, false)).collect(Collectors.toCollection(ArrayList::new)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>app-platform-subscription</artifactId>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>app-platform-subscription-domain</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-sdk</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>app-platform-subscription</artifactId>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>app-platform-subscription-infra</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-domain</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>system-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>system-application</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-pay-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-agent-core-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-knowledge-sdk</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.xspaceagi.subscription.infra.dao.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("subscription_plan")
|
||||
public class Plan {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
private BigDecimal price;
|
||||
|
||||
private BigDecimal firstPrice;
|
||||
|
||||
private Integer period;
|
||||
|
||||
private BigDecimal creditAmount;
|
||||
|
||||
private Integer callLimitCount;
|
||||
|
||||
private Boolean functionOnly;
|
||||
|
||||
private Boolean isHot;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String bizType;
|
||||
|
||||
private String bizId;
|
||||
|
||||
private String groupIds;
|
||||
|
||||
private String extra;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
@TableField("_tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
private Date created;
|
||||
|
||||
private Date modified;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.xspaceagi.subscription.infra.dao.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@TableName("user_subscription")
|
||||
public class UserSubscription {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private Long planId;
|
||||
|
||||
private BizTypeEnum bizType;
|
||||
|
||||
private String bizId;
|
||||
|
||||
private Integer period;
|
||||
|
||||
private Date startTime;
|
||||
|
||||
private Date endTime;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Integer callUsedCount;
|
||||
|
||||
private Date nextResetTime;
|
||||
|
||||
@TableField("_tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
private String extra;
|
||||
|
||||
private Date created;
|
||||
|
||||
private Date modified;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.xspaceagi.subscription.infra.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.Plan;
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanQueryRequest;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface PlanMapper extends BaseMapper<Plan> {
|
||||
|
||||
List<Plan> selectListWithFilters(@Param("query") PlanQueryRequest query);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.xspaceagi.subscription.infra.dao.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.UserSubscription;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface UserSubscriptionMapper extends BaseMapper<UserSubscription> {
|
||||
|
||||
@Select("SELECT * FROM user_subscription WHERE user_id = #{userId} AND plan_id = #{planId}")
|
||||
UserSubscription selectByUserIdAndPlanId(@Param("userId") Long userId, @Param("planId") Long planId);
|
||||
|
||||
@Update("UPDATE user_subscription SET end_time = #{endTime}, modified = NOW() WHERE id = #{id}")
|
||||
int updateEndTime(@Param("id") Long id, @Param("endTime") Date endTime);
|
||||
|
||||
@Update("UPDATE user_subscription SET start_time = #{startTime}, end_time = #{endTime}, status = #{status}, modified = NOW() WHERE id = #{id}")
|
||||
int updatePeriod(@Param("id") Long id, @Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime, @Param("status") Integer status);
|
||||
|
||||
java.util.Map<String, Object> selectStatsByPlanBiz(@Param("bizType") String bizType,
|
||||
@Param("bizId") String bizId,
|
||||
@Param("todayStart") java.util.Date todayStart,
|
||||
@Param("monthStart") java.util.Date monthStart);
|
||||
|
||||
List<UserSubscription> selectByPlanBiz(@Param("bizType") String bizType,
|
||||
@Param("bizId") String bizId,
|
||||
@Param("offset") int offset,
|
||||
@Param("limit") int limit);
|
||||
|
||||
Long countByPlanBiz(@Param("bizType") String bizType,
|
||||
@Param("bizId") String bizId);
|
||||
|
||||
@Update("UPDATE user_subscription SET call_used_count = 0, next_reset_time = #{nextResetTime}, modified = NOW() WHERE id = #{id}")
|
||||
int resetCallCount(@Param("id") Long id, @Param("nextResetTime") Date nextResetTime);
|
||||
|
||||
@Update("UPDATE user_subscription SET call_used_count = call_used_count + #{count}, modified = NOW() WHERE id = #{id}")
|
||||
int incrementCallCount(@Param("id") Long id, @Param("count") Integer count);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.xspaceagi.subscription.infra.dao.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.Plan;
|
||||
|
||||
public interface IPlanService extends IService<Plan> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.xspaceagi.subscription.infra.dao.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.UserSubscription;
|
||||
|
||||
public interface IUserSubscriptionService extends IService<UserSubscription> {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.xspaceagi.subscription.infra.dao.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.Plan;
|
||||
import com.xspaceagi.subscription.infra.dao.mapper.PlanMapper;
|
||||
import com.xspaceagi.subscription.infra.dao.service.IPlanService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements IPlanService {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.xspaceagi.subscription.infra.dao.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.xspaceagi.subscription.infra.dao.entity.UserSubscription;
|
||||
import com.xspaceagi.subscription.infra.dao.mapper.UserSubscriptionMapper;
|
||||
import com.xspaceagi.subscription.infra.dao.service.IUserSubscriptionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UserSubscriptionServiceImpl extends ServiceImpl<UserSubscriptionMapper, UserSubscription> implements IUserSubscriptionService {
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xspaceagi.subscription.infra.dao.mapper.PlanMapper">
|
||||
|
||||
<select id="selectListWithFilters" resultType="com.xspaceagi.subscription.infra.dao.entity.Plan">
|
||||
SELECT * FROM subscription_plan
|
||||
<where>
|
||||
<if test="query.bizType != null">AND biz_type = #{query.bizType.code}</if>
|
||||
<if test="query.bizId != null">AND biz_id = #{query.bizId}</if>
|
||||
<if test="query.status != null">AND status = #{query.status}</if>
|
||||
<if test="query.keyword != null and query.keyword != ''">
|
||||
AND name LIKE CONCAT('%', #{query.keyword}, '%')
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY sort ASC, id ASC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.xspaceagi.subscription.infra.dao.mapper.UserSubscriptionMapper">
|
||||
|
||||
<select id="selectStatsByPlanBiz" resultType="java.util.HashMap">
|
||||
SELECT
|
||||
COUNT(*) AS totalCount,
|
||||
SUM(CASE WHEN us.created >= #{todayStart} THEN 1 ELSE 0 END) AS todayCount,
|
||||
SUM(CASE WHEN us.created >= #{monthStart} THEN 1 ELSE 0 END) AS monthCount
|
||||
FROM user_subscription us
|
||||
INNER JOIN subscription_plan sp ON us.plan_id = sp.id
|
||||
WHERE sp.biz_type = #{bizType} AND sp.biz_id = #{bizId}
|
||||
</select>
|
||||
|
||||
<select id="selectByPlanBiz" resultType="com.xspaceagi.subscription.infra.dao.entity.UserSubscription">
|
||||
SELECT us.*
|
||||
FROM user_subscription us
|
||||
WHERE us.biz_type = #{bizType} AND us.biz_id = #{bizId}
|
||||
ORDER BY us.created DESC
|
||||
LIMIT #{offset}, #{limit}
|
||||
</select>
|
||||
|
||||
<select id="countByPlanBiz" resultType="java.lang.Long">
|
||||
SELECT COUNT(*)
|
||||
FROM user_subscription us
|
||||
INNER JOIN subscription_plan sp ON us.plan_id = sp.id
|
||||
WHERE sp.biz_type = #{bizType} AND sp.biz_id = #{bizId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>app-platform-subscription-sdk</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.xspaceagi.subscription.sdk.dto;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
@Schema(description = "创建订阅请求")
|
||||
public class CreateSubscriptionRequest implements Serializable {
|
||||
|
||||
@Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "计划ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long planId;
|
||||
|
||||
@Schema(description = "业务类型")
|
||||
private BizTypeEnum bizType;
|
||||
|
||||
@Schema(description = "扩展信息,记录订阅快照等")
|
||||
private Map<String, Object> extra;
|
||||
|
||||
public String getExtraJsonString() {
|
||||
return extra == null ? null : JSON.toJSONString(extra);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.xspaceagi.subscription.sdk.dto;
|
||||
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import com.xspaceagi.subscription.spec.enums.PlanPeriodEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
@Schema(description = "订阅计划信息")
|
||||
public class PlanDTO implements Serializable {
|
||||
|
||||
@Schema(description = "计划ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "计划名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "计划描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "价格")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "首次订阅价格")
|
||||
private BigDecimal firstPrice;
|
||||
|
||||
@Schema(description = "周期:1-月,3-季度,12-年")
|
||||
private PlanPeriodEnum period;
|
||||
|
||||
@Schema(description = "每月赠送积分")
|
||||
private BigDecimal creditAmount;
|
||||
|
||||
@Schema(description = "可调用次数,-1表示不限制")
|
||||
private Integer callLimitCount;
|
||||
|
||||
@Schema(description = "是否仅为功能订阅(true时资源消耗费用另计)")
|
||||
private Boolean functionOnly;
|
||||
|
||||
//从全局配置读取,无需字段存储
|
||||
@Schema(description = "每日登录赠送积分")
|
||||
private BigDecimal dailyGiftCreditAmount;
|
||||
|
||||
@Schema(description = "是否热门")
|
||||
private Boolean isHot;
|
||||
|
||||
@Schema(description = "状态:0-下线,1-上线")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "业务类型:SYSTEM-系统,AGENT-智能体,SKILL-技能")
|
||||
private BizTypeEnum bizType;
|
||||
|
||||
@Schema(description = "业务对象ID,非SYSTEM时必填")
|
||||
private String bizId;
|
||||
|
||||
@Schema(description = "关联用户组ID(JSON数组)")
|
||||
private List<Long> groupIds;
|
||||
|
||||
@Schema(description = "扩展字段(JSON)")
|
||||
private Map<String, Object> extra;
|
||||
|
||||
@Schema(description = "排序,越小越靠前,前端支持拖拽")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date created;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
private Date modified;
|
||||
|
||||
@Schema(description = "订阅计划的权限分组项")
|
||||
private List<PlanItemGroupDTO> itemGroups;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.xspaceagi.subscription.sdk.dto;
|
||||
|
||||
import com.xspaceagi.system.sdk.service.dto.MergedGroupDataPermissionDto;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class PlanItemGroupDTO {
|
||||
@Schema(description = "分组描述")
|
||||
private String name;
|
||||
@Schema(description = "分组描述")
|
||||
private String description;
|
||||
@Schema(description = "分组类型")
|
||||
private GroupType groupType;
|
||||
@Schema(description = "分组项")
|
||||
private List<ItemDTO> items;
|
||||
@Schema(description = "有权限访问的开放 API, groupType为API时有效")
|
||||
private List<MergedGroupDataPermissionDto.OpenApiConfig> openApiConfigs;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
public static class ItemDTO {
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
@Schema(description = "图标")
|
||||
private String icon;
|
||||
@Schema(description = "是否选中")
|
||||
private boolean selected;
|
||||
}
|
||||
|
||||
public enum GroupType {
|
||||
BASE,
|
||||
MODEL,
|
||||
AGENT,
|
||||
APP,
|
||||
KB,
|
||||
API,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.xspaceagi.subscription.sdk.dto;
|
||||
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Data
|
||||
@Schema(description = "订阅计划查询请求")
|
||||
public class PlanQueryRequest implements Serializable {
|
||||
|
||||
@Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "业务类型过滤")
|
||||
private BizTypeEnum bizType;
|
||||
|
||||
@Schema(description = "业务对象ID过滤")
|
||||
private String bizId;
|
||||
|
||||
@Schema(description = "状态过滤:0-下线,1-上线")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "关键词搜索(名称)")
|
||||
private String keyword;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.xspaceagi.subscription.sdk.dto;
|
||||
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Schema(description = "用户订阅查询请求")
|
||||
public class SubscriptionQueryRequest implements Serializable {
|
||||
|
||||
@Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "业务类型过滤")
|
||||
private BizTypeEnum bizType;
|
||||
|
||||
@Schema(description = "业务ID过滤")
|
||||
private String bizId;
|
||||
|
||||
@Schema(description = "状态过滤:0-生效中,1-已过期,2-已取消")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否展示计划详细描述列表")
|
||||
private boolean showPlanDescItems;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.xspaceagi.subscription.sdk.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Schema(description = "订阅统计")
|
||||
public class SubscriptionStatsDTO implements Serializable {
|
||||
|
||||
@Schema(description = "总订阅数")
|
||||
private Long totalCount;
|
||||
|
||||
@Schema(description = "今日新订阅数")
|
||||
private Long todayCount;
|
||||
|
||||
@Schema(description = "本月新订阅数")
|
||||
private Long monthCount;
|
||||
|
||||
@Schema(description = "订阅用户列表")
|
||||
private List<UserSubscriptionDTO> subscribers;
|
||||
|
||||
@Schema(description = "总记录数(分页)")
|
||||
private Long total;
|
||||
|
||||
@Schema(description = "当前页码")
|
||||
private Integer pageNum;
|
||||
|
||||
@Schema(description = "每页数量")
|
||||
private Integer pageSize;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.xspaceagi.subscription.sdk.dto;
|
||||
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Schema(description = "订阅统计查询请求")
|
||||
public class SubscriptionStatsQueryRequest implements Serializable {
|
||||
|
||||
@Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private BizTypeEnum bizType;
|
||||
|
||||
@Schema(description = "业务对象ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String bizId;
|
||||
|
||||
@Schema(description = "页码,从1开始")
|
||||
private Integer pageNum = 1;
|
||||
|
||||
@Schema(description = "每页数量")
|
||||
private Integer pageSize = 20;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.xspaceagi.subscription.sdk.dto;
|
||||
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import com.xspaceagi.subscription.spec.enums.PlanPeriodEnum;
|
||||
import com.xspaceagi.subscription.spec.enums.SubscriptionStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@Schema(description = "用户订阅信息")
|
||||
public class UserSubscriptionDTO implements Serializable {
|
||||
|
||||
@Schema(description = "订阅记录ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "租户ID")
|
||||
private Long tenantId;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "计划ID")
|
||||
private Long planId;
|
||||
|
||||
@Schema(description = "计划名称")
|
||||
private String planName;
|
||||
|
||||
private BizTypeEnum bizType;
|
||||
|
||||
private String bizId;
|
||||
|
||||
@Schema(description = "业务对象名称")
|
||||
private String bizName;
|
||||
|
||||
@Schema(description = "图标")
|
||||
private String icon;
|
||||
|
||||
@Schema(description = "周期:1-月,3-季度,12-年")
|
||||
private PlanPeriodEnum period;
|
||||
|
||||
@Schema(description = "开始时间")
|
||||
private Date startTime;
|
||||
|
||||
@Schema(description = "结束时间,为空时为买断,永不过期")
|
||||
private Date endTime;
|
||||
|
||||
@Schema(description = "状态:0-生效中,1-已过期,2-已取消")
|
||||
private SubscriptionStatusEnum status;
|
||||
|
||||
@Schema(description = "计划订阅时的快照")
|
||||
private PlanDTO plan;
|
||||
|
||||
@Schema(description = "已使用调用次数")
|
||||
private Integer callUsedCount;
|
||||
|
||||
@Schema(description = "下次重置时间(每月重置)")
|
||||
private Date nextResetTime;
|
||||
|
||||
@Schema(description = "扩展字段,记录订阅快照等")
|
||||
private Map<String, Object> extra;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date created;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
private Date modified;
|
||||
|
||||
@Schema(description = "订阅者信息")
|
||||
private Subscriber subscriber;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class Subscriber {
|
||||
@Schema(description = "订阅者ID")
|
||||
private Long id;
|
||||
@Schema(description = "订阅者名称")
|
||||
private String name;
|
||||
@Schema(description = "订阅者头像")
|
||||
private String avatar;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.xspaceagi.subscription.sdk.rpc;
|
||||
|
||||
import com.xspaceagi.subscription.sdk.dto.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ISubscriptionRpcService {
|
||||
|
||||
/**
|
||||
* 查询用户当前订阅信息(可指定业务类型)
|
||||
*/
|
||||
List<UserSubscriptionDTO> getUserSubscriptions(SubscriptionQueryRequest request);
|
||||
|
||||
/**
|
||||
* 获取用户当前系统订阅
|
||||
*/
|
||||
UserSubscriptionDTO getUserCurrentSystemSubscription(Long userId);
|
||||
|
||||
/**
|
||||
* 创建用户订阅(内部判断新建、续期、升级、变更计划)
|
||||
*/
|
||||
UserSubscriptionDTO createSubscription(CreateSubscriptionRequest request);
|
||||
|
||||
/**
|
||||
* 创建订阅计划
|
||||
*/
|
||||
Long createPlan(PlanDTO dto);
|
||||
|
||||
/**
|
||||
* 修改订阅计划
|
||||
*/
|
||||
boolean updatePlan(PlanDTO dto);
|
||||
|
||||
/**
|
||||
* 下架订阅计划
|
||||
*/
|
||||
boolean offlinePlan(Long tenantId, Long planId);
|
||||
|
||||
PlanDTO getPlan(Long planId);
|
||||
|
||||
/**
|
||||
* 查询订阅计划列表
|
||||
*/
|
||||
List<PlanDTO> listPlans(PlanQueryRequest request);
|
||||
|
||||
/**
|
||||
* 增加订阅调用次数(自动判断是否需要月度重置)
|
||||
*/
|
||||
int incrementCallCount(Long tenantId, Long subscriptionId, Integer count);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>app-platform-subscription</artifactId>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>app-platform-subscription-spec</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>system-sdk</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.xspaceagi.subscription.spec.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum BizTypeEnum {
|
||||
|
||||
SYSTEM("SYSTEM", "系统全局"),
|
||||
AGENT("AGENT", "智能体"),
|
||||
SKILL("SKILL", "技能");
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
public static BizTypeEnum fromCode(String code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (BizTypeEnum e : values()) {
|
||||
if (e.getCode().equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.xspaceagi.subscription.spec.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PlanPeriodEnum {
|
||||
|
||||
MONTH(1, "月"),
|
||||
QUARTER(3, "季度"),
|
||||
YEAR(12, "年"),
|
||||
FOREVER(0, "永久");
|
||||
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
|
||||
public static PlanPeriodEnum getByCode(Integer code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (PlanPeriodEnum e : values()) {
|
||||
if (e.getCode().equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.xspaceagi.subscription.spec.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PlanStatusEnum {
|
||||
|
||||
OFFLINE(0, "下线"),
|
||||
ONLINE(1, "上线");
|
||||
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
|
||||
public boolean isOnline() {
|
||||
return ONLINE.equals(this);
|
||||
}
|
||||
|
||||
public static PlanStatusEnum getByCode(Integer code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (PlanStatusEnum e : values()) {
|
||||
if (e.getCode().equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.xspaceagi.subscription.spec.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SubscriptionStatusEnum {
|
||||
|
||||
ACTIVE(0, "生效中"),
|
||||
EXPIRED(1, "已过期"),
|
||||
CANCELLED(2, "已取消");
|
||||
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
|
||||
public static SubscriptionStatusEnum getByCode(Integer code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (SubscriptionStatusEnum e : values()) {
|
||||
if (e.getCode().equals(code)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>app-platform-subscription</artifactId>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>app-platform-subscription-web</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-application</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-agent-core-sdk</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-bill-sdk</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.xspaceagi.subscription.web.controller;
|
||||
|
||||
import com.xspaceagi.agent.core.sdk.IAgentRpcService;
|
||||
import com.xspaceagi.agent.core.sdk.dto.AgentInfoDto;
|
||||
import com.xspaceagi.subscription.app.service.SubscriptionPlanAppService;
|
||||
import com.xspaceagi.subscription.app.service.UserSubscriptionAppService;
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanDTO;
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanQueryRequest;
|
||||
import com.xspaceagi.subscription.sdk.dto.SubscriptionStatsDTO;
|
||||
import com.xspaceagi.subscription.sdk.dto.SubscriptionStatsQueryRequest;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import com.xspaceagi.subscription.web.controller.dto.SortUpdateDTO;
|
||||
import com.xspaceagi.system.sdk.permission.SpacePermissionService;
|
||||
import com.xspaceagi.system.spec.dto.ReqResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/agent/plan")
|
||||
@Tag(name = "智能体订阅计划管理")
|
||||
public class AgentPlanManController {
|
||||
|
||||
@Resource
|
||||
private SubscriptionPlanAppService subscriptionPlanAppService;
|
||||
|
||||
@Resource
|
||||
private UserSubscriptionAppService userSubscriptionAppService;
|
||||
|
||||
@Resource
|
||||
private IAgentRpcService iAgentRpcService;
|
||||
|
||||
@Resource
|
||||
private SpacePermissionService spacePermissionService;
|
||||
|
||||
@GetMapping("/subscription/stats")
|
||||
@Operation(summary = "查询智能体订阅统计")
|
||||
public ReqResult<SubscriptionStatsDTO> getSubscriptionStats(
|
||||
@RequestParam Long agentId,
|
||||
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(defaultValue = "20") Integer pageSize) {
|
||||
checkAgentPermission(agentId);
|
||||
SubscriptionStatsQueryRequest request = new SubscriptionStatsQueryRequest();
|
||||
request.setBizType(BizTypeEnum.AGENT);
|
||||
request.setBizId(agentId.toString());
|
||||
request.setPageNum(pageNum);
|
||||
request.setPageSize(pageSize);
|
||||
return ReqResult.success(userSubscriptionAppService.getSubscriptionStats(request));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/create")
|
||||
@Operation(summary = "添加订阅计划")
|
||||
public ReqResult<Long> createPlan(@RequestBody PlanDTO dto) {
|
||||
Assert.notNull(dto.getBizId(), "智能体ID不能为空");
|
||||
dto.setBizType(BizTypeEnum.AGENT);
|
||||
checkAgentPermission(Long.parseLong(dto.getBizId()));
|
||||
return ReqResult.success(subscriptionPlanAppService.createPlan(dto));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/update")
|
||||
@Operation(summary = "修改订阅计划")
|
||||
public ReqResult<Boolean> updatePlan(@RequestBody PlanDTO dto) {
|
||||
Assert.notNull(dto.getId(), "计划ID不能为空");
|
||||
dto.setBizId(null);
|
||||
dto.setBizType(BizTypeEnum.AGENT);
|
||||
PlanDTO planById = subscriptionPlanAppService.getPlanById(dto.getId());
|
||||
Assert.isTrue(planById != null && planById.getBizType() == BizTypeEnum.AGENT, "计划不存在");
|
||||
checkAgentPermission(Long.parseLong(planById.getBizId()));
|
||||
return ReqResult.success(subscriptionPlanAppService.updatePlan(dto));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/sort/update")
|
||||
@Operation(summary = "修改订阅计划排序")
|
||||
public ReqResult<Void> updatePlanSort(@RequestBody List<SortUpdateDTO> updateDTOS) {
|
||||
updateDTOS.forEach(updateDTO -> {
|
||||
PlanDTO planById = subscriptionPlanAppService.getPlanById(updateDTO.getId());
|
||||
Assert.isTrue(planById != null && planById.getBizType() == BizTypeEnum.AGENT, "计划不存在");
|
||||
checkAgentPermission(Long.parseLong(planById.getBizId()));
|
||||
PlanDTO dto = new PlanDTO();
|
||||
dto.setId(updateDTO.getId());
|
||||
dto.setSort(updateDTO.getSort());
|
||||
subscriptionPlanAppService.updatePlan(dto);
|
||||
});
|
||||
return ReqResult.success();
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询订阅计划列表")
|
||||
public ReqResult<List<PlanDTO>> listPlans(
|
||||
@RequestParam Long agentId,
|
||||
@RequestParam(required = false) Integer status,
|
||||
@RequestParam(required = false) String keyword) {
|
||||
PlanQueryRequest query = new PlanQueryRequest();
|
||||
query.setBizType(BizTypeEnum.AGENT);
|
||||
query.setBizId(agentId.toString());
|
||||
query.setStatus(status);
|
||||
query.setKeyword(keyword);
|
||||
return ReqResult.success(subscriptionPlanAppService.listPlans(query));
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/offline")
|
||||
@Operation(summary = "下架订阅计划")
|
||||
public ReqResult<Boolean> offlinePlan(@PathVariable Long id) {
|
||||
PlanDTO planById = subscriptionPlanAppService.getPlanById(id);
|
||||
Assert.isTrue(planById != null && planById.getBizType() == BizTypeEnum.AGENT, "计划不存在");
|
||||
checkAgentPermission(Long.parseLong(planById.getBizId()));
|
||||
return ReqResult.success(subscriptionPlanAppService.offlinePlan(id));
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/delete")
|
||||
@Operation(summary = "删除订阅计划")
|
||||
public ReqResult<Boolean> deletePlan(@PathVariable Long id) {
|
||||
PlanDTO planById = subscriptionPlanAppService.getPlanById(id);
|
||||
Assert.isTrue(planById != null && planById.getBizType() == BizTypeEnum.AGENT, "计划不存在");
|
||||
checkAgentPermission(Long.parseLong(planById.getBizId()));
|
||||
return ReqResult.success(subscriptionPlanAppService.deletePlan(id));
|
||||
}
|
||||
|
||||
private void checkAgentPermission(Long agentId) {
|
||||
com.xspaceagi.agent.core.sdk.dto.ReqResult<List<AgentInfoDto>> listReqResult = iAgentRpcService.queryAgentInfoList(List.of(agentId));
|
||||
if (listReqResult.getData() == null || listReqResult.getData().isEmpty()) {
|
||||
throw new IllegalArgumentException("错误的智能体ID");
|
||||
}
|
||||
spacePermissionService.checkSpaceUserPermission(listReqResult.getData().get(0).getSpaceId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package com.xspaceagi.subscription.web.controller;
|
||||
|
||||
import com.xspaceagi.agent.core.sdk.IAgentRpcService;
|
||||
import com.xspaceagi.agent.core.sdk.dto.AgentInfoDto;
|
||||
import com.xspaceagi.agent.core.sdk.dto.SkillInfoDto;
|
||||
import com.xspaceagi.bill.sdk.dto.CreateOrderRequest;
|
||||
import com.xspaceagi.bill.sdk.dto.OrderDTO;
|
||||
import com.xspaceagi.bill.sdk.rpc.IBillRpcService;
|
||||
import com.xspaceagi.bill.spec.enums.TargetTypeEnum;
|
||||
import com.xspaceagi.subscription.api.rpc.SubscriptionRpcService;
|
||||
import com.xspaceagi.subscription.app.service.SubscriptionPlanAppService;
|
||||
import com.xspaceagi.subscription.app.service.UserSubscriptionAppService;
|
||||
import com.xspaceagi.subscription.sdk.dto.*;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import com.xspaceagi.subscription.web.controller.dto.MySubscriptionDTO;
|
||||
import com.xspaceagi.system.application.util.DefaultIconUrlUtil;
|
||||
import com.xspaceagi.system.spec.common.RequestContext;
|
||||
import com.xspaceagi.system.spec.dto.ReqResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/subscription")
|
||||
@Tag(name = "用户订阅相关接口")
|
||||
public class SubscriptionController {
|
||||
|
||||
@Resource
|
||||
private UserSubscriptionAppService userSubscriptionAppService;
|
||||
|
||||
@Resource
|
||||
private SubscriptionPlanAppService subscriptionPlanAppService;
|
||||
|
||||
@Resource
|
||||
private SubscriptionRpcService subscriptionRpcService;
|
||||
|
||||
@Resource
|
||||
private IBillRpcService iBillRpcService;
|
||||
|
||||
@Resource
|
||||
private IAgentRpcService iAgentRpcService;
|
||||
|
||||
@PostMapping("/order/create")
|
||||
@Operation(summary = "创建订阅订单")
|
||||
public ReqResult<OrderDTO> createOrder(@RequestParam Long planId) {
|
||||
PlanDTO planDTO = subscriptionPlanAppService.getPlanById(planId);
|
||||
if (planDTO == null) {
|
||||
return ReqResult.error("Invalid planId");
|
||||
}
|
||||
if (planDTO.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
RequestContext<Object> ctx = RequestContext.get();
|
||||
CreateSubscriptionRequest request = new CreateSubscriptionRequest();
|
||||
request.setTenantId(ctx.getTenantId());
|
||||
request.setUserId(ctx.getUserId());
|
||||
request.setPlanId(planId);
|
||||
request.setBizType(planDTO.getBizType());
|
||||
request.setExtra(Map.of("plan", planDTO));
|
||||
subscriptionRpcService.createSubscription(request);
|
||||
return ReqResult.success();
|
||||
}
|
||||
CreateOrderRequest request = new CreateOrderRequest();
|
||||
request.setTenantId(RequestContext.get().getTenantId());
|
||||
request.setUserId(RequestContext.get().getUserId());
|
||||
request.setDescription("订阅[" + planDTO.getName() + "]");
|
||||
request.setBizType(com.xspaceagi.bill.spec.enums.BizTypeEnum.SUBSCRIPTION);
|
||||
CreateOrderRequest.CreateOrderItem item = new CreateOrderRequest.CreateOrderItem();
|
||||
item.setTargetName(planDTO.getName());
|
||||
item.setTargetType(TargetTypeEnum.PLAN.getCode());
|
||||
item.setTargetId(planDTO.getId());
|
||||
item.setPrice(planDTO.getPrice());
|
||||
item.setCount(1);
|
||||
item.setSnapshot(Map.of("plan", planDTO));
|
||||
request.setItems(List.of(item));
|
||||
OrderDTO order = iBillRpcService.createOrder(request);
|
||||
return ReqResult.success(order);
|
||||
}
|
||||
|
||||
@GetMapping("/system/plans")
|
||||
@Operation(summary = "查询可订阅的系统计划列表")
|
||||
public ReqResult<List<PlanDTO>> listPlans() {
|
||||
PlanQueryRequest query = new PlanQueryRequest();
|
||||
query.setBizType(BizTypeEnum.SYSTEM);
|
||||
query.setBizId(null);
|
||||
query.setStatus(1);
|
||||
return ReqResult.success(subscriptionPlanAppService.listPlans(query));
|
||||
}
|
||||
|
||||
@GetMapping("/my")
|
||||
@Operation(summary = "查询我的订阅")
|
||||
public ReqResult<MySubscriptionDTO> getMySubscriptions(@RequestParam(required = false) BizTypeEnum bizType, @RequestParam(required = false) String bizId) {
|
||||
SubscriptionQueryRequest query = new SubscriptionQueryRequest();
|
||||
query.setUserId(RequestContext.get().getUserId());
|
||||
query.setBizType(bizType);
|
||||
query.setBizId(bizId);
|
||||
if (bizType == null) {
|
||||
query.setBizType(BizTypeEnum.SYSTEM);
|
||||
query.setBizId(null);
|
||||
}
|
||||
List<UserSubscriptionDTO> subscriptions = userSubscriptionAppService.getUserSubscriptions(query);
|
||||
MySubscriptionDTO dto = new MySubscriptionDTO();
|
||||
dto.setSubscriptions(subscriptions);
|
||||
if (bizType == BizTypeEnum.SYSTEM || StringUtils.isNotBlank(bizId)) {
|
||||
dto.setCurrentSubscription(subscriptions.stream().findFirst().orElse(null));
|
||||
}
|
||||
if (bizType == BizTypeEnum.AGENT && CollectionUtils.isNotEmpty(subscriptions)) {
|
||||
List<Long> agentIds = subscriptions.stream().map(subscriptionDTO -> Long.parseLong(subscriptionDTO.getBizId())).collect(Collectors.toList());
|
||||
Map<Long, AgentInfoDto> agentInfoDtoMap = iAgentRpcService.queryAgentInfoList(agentIds).getData().stream().collect(Collectors.toMap(AgentInfoDto::getId, agentInfoDto -> agentInfoDto, (a, b) -> a));
|
||||
subscriptions.forEach(subscriptionDTO -> {
|
||||
AgentInfoDto agentInfoDto = agentInfoDtoMap.get(Long.parseLong(subscriptionDTO.getBizId()));
|
||||
if (agentInfoDto != null) {
|
||||
subscriptionDTO.setBizName(agentInfoDto.getName());
|
||||
subscriptionDTO.setIcon(DefaultIconUrlUtil.setDefaultIconUrl(agentInfoDto.getIcon(), agentInfoDto.getName(), "agent"));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (bizType == BizTypeEnum.SKILL && CollectionUtils.isNotEmpty(subscriptions)) {
|
||||
subscriptions.forEach(subscriptionDTO -> {
|
||||
SkillInfoDto publishedSkillInfo = iAgentRpcService.getPublishedSkillInfo(Long.parseLong(subscriptionDTO.getBizId()), null).getData();
|
||||
if (publishedSkillInfo != null) {
|
||||
subscriptionDTO.setBizName(publishedSkillInfo.getName());
|
||||
subscriptionDTO.setIcon(DefaultIconUrlUtil.setDefaultIconUrl(publishedSkillInfo.getIcon(), publishedSkillInfo.getName(), "skill"));
|
||||
}
|
||||
});
|
||||
}
|
||||
return ReqResult.success(dto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.xspaceagi.subscription.web.controller;
|
||||
|
||||
import com.xspaceagi.subscription.app.service.SubscriptionPlanAppService;
|
||||
import com.xspaceagi.subscription.app.service.UserSubscriptionAppService;
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanDTO;
|
||||
import com.xspaceagi.subscription.sdk.dto.PlanQueryRequest;
|
||||
import com.xspaceagi.subscription.sdk.dto.SubscriptionStatsDTO;
|
||||
import com.xspaceagi.subscription.sdk.dto.SubscriptionStatsQueryRequest;
|
||||
import com.xspaceagi.subscription.spec.enums.BizTypeEnum;
|
||||
import com.xspaceagi.subscription.web.controller.dto.SortUpdateDTO;
|
||||
import com.xspaceagi.system.spec.annotation.RequireResource;
|
||||
import com.xspaceagi.system.spec.dto.ReqResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.xspaceagi.system.spec.enums.ResourceEnum.*;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/system/plan")
|
||||
@Tag(name = "系统订阅计划管理")
|
||||
public class SystemPlanManController {
|
||||
|
||||
@Resource
|
||||
private SubscriptionPlanAppService subscriptionPlanAppService;
|
||||
|
||||
@Resource
|
||||
private UserSubscriptionAppService userSubscriptionAppService;
|
||||
|
||||
@RequireResource(SUBSCRIPTION_POINTS_QUERY)
|
||||
@GetMapping("/subscription/stats")
|
||||
@Operation(summary = "查询指定对象的订阅统计")
|
||||
public ReqResult<SubscriptionStatsDTO> getSubscriptionStats(
|
||||
@RequestParam BizTypeEnum bizType,
|
||||
@RequestParam String bizId,
|
||||
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(defaultValue = "20") Integer pageSize) {
|
||||
SubscriptionStatsQueryRequest request = new SubscriptionStatsQueryRequest();
|
||||
request.setBizType(bizType);
|
||||
request.setBizId(bizId);
|
||||
request.setPageNum(pageNum);
|
||||
request.setPageSize(pageSize);
|
||||
return ReqResult.success(userSubscriptionAppService.getSubscriptionStats(request));
|
||||
}
|
||||
|
||||
@RequireResource(SUBSCRIPTION_POINTS_MODIFY)
|
||||
@PostMapping(value = "/create")
|
||||
@Operation(summary = "添加订阅计划")
|
||||
public ReqResult<Long> createPlan(@RequestBody PlanDTO dto) {
|
||||
dto.setBizType(BizTypeEnum.SYSTEM);
|
||||
return ReqResult.success(subscriptionPlanAppService.createPlan(dto));
|
||||
}
|
||||
|
||||
@RequireResource(SUBSCRIPTION_POINTS_MODIFY)
|
||||
@PostMapping(value = "/update")
|
||||
@Operation(summary = "修改订阅计划")
|
||||
public ReqResult<Boolean> updatePlan(@RequestBody PlanDTO dto) {
|
||||
return ReqResult.success(subscriptionPlanAppService.updatePlan(dto));
|
||||
}
|
||||
|
||||
@RequireResource(SUBSCRIPTION_POINTS_MODIFY)
|
||||
@PostMapping(value = "/sort/update")
|
||||
@Operation(summary = "修改订阅计划排序")
|
||||
public ReqResult<Void> updatePlanSort(@RequestBody List<SortUpdateDTO> updateDTOS) {
|
||||
updateDTOS.forEach(updateDTO -> {
|
||||
PlanDTO dto = new PlanDTO();
|
||||
dto.setId(updateDTO.getId());
|
||||
dto.setSort(updateDTO.getSort());
|
||||
subscriptionPlanAppService.updatePlan(dto);
|
||||
});
|
||||
return ReqResult.success();
|
||||
}
|
||||
|
||||
@RequireResource(SUBSCRIPTION_POINTS_QUERY)
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询订阅计划列表")
|
||||
public ReqResult<List<PlanDTO>> listPlans(
|
||||
@RequestParam(required = false) Integer status,
|
||||
@RequestParam(required = false) String keyword) {
|
||||
PlanQueryRequest query = new PlanQueryRequest();
|
||||
query.setBizType(BizTypeEnum.SYSTEM);
|
||||
query.setStatus(status);
|
||||
query.setKeyword(keyword);
|
||||
return ReqResult.success(subscriptionPlanAppService.listPlans(query));
|
||||
}
|
||||
|
||||
@RequireResource(SUBSCRIPTION_POINTS_MODIFY)
|
||||
@PostMapping("/{id}/offline")
|
||||
@Operation(summary = "下架订阅计划")
|
||||
public ReqResult<Boolean> offlinePlan(@PathVariable Long id) {
|
||||
return ReqResult.success(subscriptionPlanAppService.offlinePlan(id));
|
||||
}
|
||||
|
||||
@RequireResource(SUBSCRIPTION_POINTS_DELETE)
|
||||
@PostMapping("/{id}/delete")
|
||||
@Operation(summary = "删除订阅计划")
|
||||
public ReqResult<Boolean> deletePlan(@PathVariable Long id) {
|
||||
return ReqResult.success(subscriptionPlanAppService.deletePlan(id));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.xspaceagi.subscription.web.controller.dto;
|
||||
|
||||
import com.xspaceagi.subscription.sdk.dto.UserSubscriptionDTO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class MySubscriptionDTO {
|
||||
|
||||
@Schema(description = "当前订阅")
|
||||
private UserSubscriptionDTO currentSubscription;
|
||||
|
||||
@Schema(description = "所有订阅")
|
||||
private List<UserSubscriptionDTO> subscriptions;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.xspaceagi.subscription.web.controller.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SortUpdateDTO {
|
||||
|
||||
private Long id;
|
||||
private Integer sort;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-modules</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>app-platform-subscription</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>system-sdk</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-application</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-infra</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-domain</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-spec</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-sdk</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.xspaceagi</groupId>
|
||||
<artifactId>app-platform-subscription-web</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<modules>
|
||||
<module>app-platform-subscription-spec</module>
|
||||
<module>app-platform-subscription-sdk</module>
|
||||
<module>app-platform-subscription-domain</module>
|
||||
<module>app-platform-subscription-infra</module>
|
||||
<module>app-platform-subscription-application</module>
|
||||
<module>app-platform-subscription-api</module>
|
||||
<module>app-platform-subscription-web</module>
|
||||
</modules>
|
||||
</project>
|
||||
Reference in New Issue
Block a user