chore: initialize qiming workspace repository

This commit is contained in:
Codex
2026-05-29 14:22:48 +08:00
commit bfd67a0f2c
10750 changed files with 1885711 additions and 0 deletions

View File

@@ -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>

View File

@@ -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());
}
}

View File

@@ -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);
}
}

View File

@@ -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));
}
}

View File

@@ -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;
}

View File

@@ -0,0 +1,10 @@
package com.xspaceagi.subscription.web.controller.dto;
import lombok.Data;
@Data
public class SortUpdateDTO {
private Long id;
private Integer sort;
}