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,108 @@
<?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-eco-market</artifactId>
<groupId>com.xspaceagi</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-platform-eco-market-api</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-eco-market-application</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 打包插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptors>
<!-- 打包配置必须在对应目录下创建repack.xml的打包配置文件 -->
<descriptor>src/main/resources/assemblies/repack.xml</descriptor>
</descriptors>
</configuration>
</plugin>
<!-- install插件定制在mvn install过程使用哪个jar包安装到本地 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<executions>
<execution>
<id>install-file</id>
<goals>
<goal>install-file</goal>
</goals>
<phase>install</phase>
</execution>
</executions>
<configuration>
<!-- install配置指定将哪个目录下的jar包install为这个工程的jar -->
<file>${project.build.directory}/${project.build.finalName}-repack.jar</file>
<!--
install配置指定将install的jar打包使用的pom.xml文件
即其他依赖这个jar包的工程按照哪个pom.xml文件来解析依赖
-->
<pomFile>src/main/resources/install-pom.xml</pomFile>
</configuration>
</plugin>
<!-- deploy插件定制在mvn deploy过程使用哪个jar包发布到仓库 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<executions>
<execution>
<id>deploy-file</id>
<goals>
<goal>deploy-file</goal>
</goals>
<!-- 跳过默认的发布包 -->
<phase>none</phase>
</execution>
</executions>
<configuration>
<!-- deploy配置指定将哪个目录下的jar包发布为这个工程的jar -->
<file>${project.build.directory}/${project.build.finalName}-repack.jar</file>
<!-- 发布地址 -->
<url>http://local-maven.space.com/nexus/content/repositories/snapshots/</url>
<repositoryId>nexus-snapshots</repositoryId>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<packaging>jar</packaging>
<!--
deploy配置指定将deploy的jar打包使用的pom.xml文件
即其他依赖这个jar包的工程按照哪个pom.xml文件来解析依赖
-->
<pomFile>src/main/resources/install-pom.xml</pomFile>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,110 @@
package com.xspaceagi.eco.market.spec.api;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import com.xspaceagi.system.domain.service.UserDomainService;
import com.xspaceagi.system.infra.dao.entity.Tenant;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientSecretDomainService;
import com.xspaceagi.eco.market.spec.app.service.IEcoMarketClientSecretApplicationService;
import com.xspaceagi.system.spec.common.RequestContext;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.enums.TenantStatus;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
/**
* 生态市场客户端配置
*/
@Slf4j
@Configuration
public class EcoMarketClientRegisterTask {
@Resource
private IEcoMarketClientSecretDomainService ecoMarketClientSecretDomainService;
@Resource
private UserDomainService userDomainService;
@Resource
private IEcoMarketClientSecretApplicationService clientSecretApplicationService;
/**
* 定时重试失败的任务
* 每5分钟执行一次
*/
@Scheduled(fixedDelayString = "${eco.market.client.retry.interval:300}", timeUnit = TimeUnit.SECONDS)
public void scheduledRetryFailedTasks() {
log.debug("Start eco-market client secret retry");
// 查询所有的租户
List<Tenant> tenants = userDomainService.queryTenantsByStatus(TenantStatus.Enabled);
for (Tenant tenant : tenants) {
log.debug("Check client secret for tenant [{}]", tenant.getName());
processTenant(tenant);
}
}
/**
* 处理单个租户的客户端密钥注册和保存
*
* @param tenant 租户信息
*/
private void processTenant(Tenant tenant) {
try {
// 创建系统用户上下文
UserContext userContext = UserContext.builder()
.userId(0L)
.userName("system")
.tenantId(tenant.getId())
.tenantName(tenant.getName())
.build();
// 设置请求上下文
RequestContext<UserContext> requestContext = new RequestContext<>();
requestContext.setTenantId(tenant.getId());
requestContext.setUserContext(userContext);
RequestContext.set(requestContext);
var tenantId = tenant.getId();
if (Objects.isNull(tenantId)) {
log.error("Tenant [{}] id empty; cannot register client secret", tenant.getName());
return;
}
// 检查并注册客户端密钥
boolean exists = ecoMarketClientSecretDomainService.existsClientSecret(tenantId);
if (!exists) {
log.info("Tenant [{}] has no client secret; registering", tenant.getName());
try {
var clientSecret = ecoMarketClientSecretDomainService.getOrRegisterClientSecret(
tenantId,
tenant.getName(),
"生态市场客户端 - " + tenant.getName());
// 使用应用层服务保存客户端密钥到本地数据库
if (clientSecret != null) {
clientSecretApplicationService.saveClientSecretDTO(clientSecret, userContext);
log.info("Tenant [{}] client secret registered and saved", tenant.getName());
}
} catch (Exception e) {
// 注册异常
log.error("Tenant [{}] client secret register error; queued for retry", tenant.getName(), e);
}
} else {
log.debug("Tenant [{}] client secret already exists", tenant.getName());
}
} catch (Exception e) {
log.error("Client secret handling error for tenant [{}]", tenant.getName(), e);
} finally {
// 清除上下文
RequestContext.remove();
}
}
}

View File

@@ -0,0 +1,36 @@
package com.xspaceagi.eco.market.spec.api;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientSecretDomainService;
import com.xspaceagi.eco.market.sdk.reponse.ClientSecretResponse;
import com.xspaceagi.eco.market.sdk.request.ClientSecretRequest;
import com.xspaceagi.eco.market.sdk.service.IEcoMarketRpcService;
import com.xspaceagi.system.domain.log.LogRecordPrint;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 生态市场RPC服务
*/
@Slf4j
@Service
public class EcoMarketRpcService implements IEcoMarketRpcService {
@Resource
private IEcoMarketClientSecretDomainService ecoMarketClientSecretDomainService;
@LogRecordPrint(content = "查询客户端密钥")
@Override
public ClientSecretResponse queryClientSecret(ClientSecretRequest request) {
var tenantId = request.getTenantId();
var clientSecret = ecoMarketClientSecretDomainService.queryByTenantId(tenantId);
return clientSecret.toClientSecretResponse();
}
}

View File

@@ -0,0 +1,31 @@
package com.xspaceagi.eco.market.spec.api;
import com.xspaceagi.eco.market.domain.specification.EcoMarkerSecretWrapper;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.eco.market.sdk.service.IEcoMarketSecretRpcService;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import com.xspaceagi.system.domain.log.LogRecordPrint;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Service
public class EcoMarketSecretRpcService implements IEcoMarketSecretRpcService {
@Resource
private EcoMarkerSecretWrapper ecoMarkerSecretWrapper;
@LogRecordPrint(content = "注册生态市场的密钥")
@Override
public ClientSecretDTO registerClient(Long tenantId, String name, String description) {
if (Objects.isNull(tenantId)) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "租户ID");
}
return ecoMarkerSecretWrapper.registerClientSecret(tenantId, name, description);
}
}

View File

@@ -0,0 +1,160 @@
package com.xspaceagi.eco.market.spec.api.adaptor;
import com.alibaba.fastjson2.JSON;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.xspaceagi.eco.market.domain.client.EcoMarketServerApiService;
import com.xspaceagi.eco.market.domain.dto.req.UpdateAndEnableConfigReqDTO;
import com.xspaceagi.eco.market.domain.dto.resp.ServerConfigDetailRespDTO;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.spec.app.service.IEcoMarketClientConfigApplicationService;
import com.xspaceagi.eco.market.spec.app.service.IEcoMarketClientPublishConfigApplicationService;
import com.xspaceagi.eco.market.spec.enums.EcoMarketOwnedFlagEnum;
import com.xspaceagi.system.spec.common.RequestContext;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.event.PullMessageEvent;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* 生态市场消息拉取组件
* 使用Guava EventBus来异步处理消息拉取逻辑
*/
@Slf4j
@Component
public class EcoMarketPullMessage {
@Resource
private EventBus eventBus;
@Resource
private EcoMarketServerApiService ecoMarketServerApiService;
@Resource
private IEcoMarketClientPublishConfigApplicationService ecoMarketClientPublishConfigApplicationService;
@Resource
private IEcoMarketClientConfigApplicationService ecoMarketClientConfigApplicationService;
@PostConstruct
public void init() {
// 注册到EventBus
eventBus.register(this);
log.info("EcoMarketPullMessage registered on EventBus");
}
/**
* 监听消息拉取事件
*
* @param event 消息拉取事件
*/
@Subscribe
public void handlePullMessageEvent(PullMessageEvent event) {
log.info("Message pull event: {}", JSON.toJSONString(event));
try {
pullMessage(event.getUserId(), event.getTenantId());
} catch (Exception e) {
log.error("Message pull event handling failed", e);
}
}
/**
* 生态市场,租户自动启用配置
*
* @param userId 用户ID
* @param tenantId 租户ID
*/
private void pullMessage(Long userId, Long tenantId) {
log.info("Run message pull, userId: {}, tenantId: {}", userId, tenantId);
var userContext = UserContext.builder()
.userId(userId)
.tenantId(tenantId)
.userName("system")
.build();
try {
// 设置请求上下文
RequestContext<UserContext> requestContext = new RequestContext<>();
requestContext.setTenantId(tenantId);
requestContext.setUserContext(userContext);
RequestContext.set(requestContext);
// 查询自动启用配置列表
List<ServerConfigDetailRespDTO> autoConfigList = ecoMarketServerApiService.queryAutoUseConfigList();
log.debug("Eco-market tenant auto-enable: loaded auto-enable config list: {}", JSON.toJSONString(autoConfigList));
// 使用结果中的 uid 来检查本地的生态市场配置,有无配置,如果没有,则主动启用,如果已经有了,但不做任何动作
var autoUseUids = autoConfigList.stream().map(ServerConfigDetailRespDTO::getUid)
.collect(Collectors.toList());
log.info("Eco-market tenant auto-enable: loaded auto-enable config list: {}", JSON.toJSONString(autoUseUids));
// 检查本地有无启用记录,没有的话,一般需要启用
var localConfigList = ecoMarketClientPublishConfigApplicationService.queryListByUids(autoUseUids);
var localUids = localConfigList.stream()
.map(EcoMarketClientPublishConfigModel::getUid)
.collect(Collectors.toList());
// 还要检查是否是我的分享,如果是我的分享,则不处理,因为我自己分享的,不需要自动启用
var myShareConfigList = ecoMarketClientConfigApplicationService.queryListByUids(autoUseUids);
var myShareUids = myShareConfigList.stream()
.filter(config -> EcoMarketOwnedFlagEnum.YES.getCode().equals(config.getOwnedFlag()))
.map(EcoMarketClientConfigModel::getUid)
.collect(Collectors.toList());
// 如果本地没有配置,则主动启用..不管本地配置是否实际启用,只要有记录了,就不在操作自动启用,需要用户自己去手动操作
var needEnableUids = autoUseUids.stream()
.filter(uid -> !localUids.contains(uid))
.filter(uid -> !myShareUids.contains(uid))
.collect(Collectors.toList());
log.info("Eco-market tenant auto-enable, need-enable list: {}", JSON.toJSONString(needEnableUids));
for (var uid : needEnableUids) {
var configOptional = autoConfigList.stream()
.filter(config -> config.getUid().equals(uid))
.findFirst();
if (configOptional.isEmpty()) {
log.warn("Eco-market auto-enable: no config, uid: {}", uid);
continue;
}
var configJson = configOptional.get().getConfigJson();
if (configJson == null) {
log.warn("Eco-market auto-enable: empty config params, uid: {}", uid);
continue;
}
var configParamJson = configOptional.get().getConfigParamJson();
try {
var updateAndEnableConfigReqDTO = new UpdateAndEnableConfigReqDTO();
updateAndEnableConfigReqDTO.setUid(uid);
updateAndEnableConfigReqDTO.setConfigJson(configJson);
updateAndEnableConfigReqDTO.setConfigParamJson(configParamJson);
ecoMarketClientPublishConfigApplicationService.updateAndEnableConfig(updateAndEnableConfigReqDTO,
userContext);
log.info("Eco-market tenant auto-enable, update-and-enable OK, uid: {}", uid);
} catch (Exception e) {
log.error("Eco-market tenant auto-enable, update-and-enable failed, uid: {}, configParamJson: {}", uid, configParamJson, e);
}
}
log.info("Eco-market auto-enable done, userId: {}, tenantId: {}", userId, tenantId);
} catch (Exception e) {
log.error("Eco-market auto-enable error, userId: {}, tenantId: {}", userId, tenantId, e);
} finally {
RequestContext.remove();
}
}
}

View File

@@ -0,0 +1,32 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>repack</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<!--
重新打包需要包含的jar包,这个过程会解压所有的jar包并按照jar的规则重新组合成一个jar包
这里需要包含当前这个工程 ,格式是{groupId}:{artifactId}
-->
<includes>
<!-- 包含项目自己 -->
<include>com.xspaceagi:app-platform-eco-market-api</include>
<include>com.xspaceagi:app-platform-eco-market-application</include>
<include>com.xspaceagi:app-platform-eco-market-domain</include>
<include>com.xspaceagi:app-platform-eco-market-infra</include>
<include>com.xspaceagi:app-platform-eco-market-spec</include>
</includes>
<!-- 打包结果目录:/ 表示target/ -->
<outputDirectory>/</outputDirectory>
<!-- 是否解压依赖 -->
<unpack>true</unpack>
<!-- 打包的scope -->
<!-- <scope>system</scope>-->
</dependencySet>
</dependencySets>
</assembly>

View File

@@ -0,0 +1,20 @@
<?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-eco-market-api</artifactId>
<groupId>com.xspaceagi</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-platform-eco-market-api</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,26 @@
<?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-eco-market</artifactId>
<groupId>com.xspaceagi</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-platform-eco-market-application</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<dependencies>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>system-sdk</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-eco-market-infra</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,278 @@
package com.xspaceagi.eco.market.spec.app.assembler;
import java.util.Objects;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigSaveReqDTO;
import com.xspaceagi.eco.market.domain.dto.resp.ServerConfigDetailRespDTO;
import com.xspaceagi.eco.market.domain.dto.resp.ServerConfigListRespDTO;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.spec.enums.EcoMarketOwnedFlagEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketUseStatusEnum;
/**
* 生态市场客户端配置转换器
* 负责各种数据对象之间的转换
*/
public class EcoMarketClientConfigTranslator {
/**
* 将客户端配置模型转换为服务器配置保存请求DTO
*
* @param model 客户端配置模型
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 服务器配置保存请求DTO
*/
public static ServerConfigSaveReqDTO toServerConfigSaveReqDTO(EcoMarketClientConfigModel model, String clientId,
String clientSecret) {
if (model == null) {
return null;
}
ServerConfigSaveReqDTO reqDTO = new ServerConfigSaveReqDTO();
reqDTO.setUid(model.getUid());
reqDTO.setName(model.getName());
reqDTO.setDescription(model.getDescription());
reqDTO.setDataType(model.getDataType());
reqDTO.setTargetType(model.getTargetType());
reqDTO.setTargetSubType(model.getTargetSubType());
reqDTO.setTargetId(model.getTargetId());
reqDTO.setCategoryCode(model.getCategoryCode());
reqDTO.setCategoryName(model.getCategoryName());
reqDTO.setAuthor(model.getAuthor());
reqDTO.setPublishDoc(model.getPublishDoc());
reqDTO.setConfigJson(model.getConfigJson());
reqDTO.setConfigParamJson(model.getConfigParamJson());
reqDTO.setIcon(model.getIcon());
reqDTO.setClientId(clientId);
reqDTO.setClientSecret(clientSecret);
reqDTO.setPageZipUrl(model.getPageZipUrl());
return reqDTO;
}
/**
* 将客户端配置模型转换为客户端发布配置模型
*
* @param model 客户端配置模型
* @return 客户端发布配置模型
*/
public static EcoMarketClientPublishConfigModel toClientPublishConfigModel(EcoMarketClientConfigModel model) {
if (model == null) {
return null;
}
EcoMarketClientPublishConfigModel ecoMarketClientPublishConfigModel = EcoMarketClientPublishConfigModel
.builder()
.id(model.getId())
.uid(model.getUid())
.name(model.getName())
.description(model.getDescription())
.dataType(model.getDataType())
.targetType(model.getTargetType())
.targetSubType(model.getTargetSubType())
.targetId(model.getTargetId())
.categoryCode(model.getCategoryCode())
.categoryName(model.getCategoryName())
.ownedFlag(model.getOwnedFlag())
.shareStatus(model.getShareStatus())
.useStatus(model.getUseStatus())
.publishTime(model.getPublishTime())
.offlineTime(model.getOfflineTime())
.versionNumber(model.getVersionNumber())
.author(model.getAuthor())
.publishDoc(model.getPublishDoc())
.configParamJson(model.getConfigParamJson())
.configJson(model.getConfigJson())
.icon(model.getIcon())
.tenantId(model.getTenantId())
.createClientId(model.getCreateClientId())
.created(model.getCreated())
.creatorId(model.getCreatorId())
.creatorName(model.getCreatorName())
.modified(model.getModified())
.modifiedId(model.getModifiedId())
.modifiedName(model.getModifiedName())
.build();
return ecoMarketClientPublishConfigModel;
}
/**
* 将服务器配置详情转换为客户端发布配置模型
*
* @param model 发布配置详情
* @return 客户端配置模型
*/
public static EcoMarketClientConfigModel toClientConfigModel(EcoMarketClientPublishConfigModel model) {
if (model == null) {
return null;
}
EcoMarketClientConfigModel ecoMarketClientConfigModel = EcoMarketClientConfigModel.builder()
.id(model.getId())
.uid(model.getUid())
.name(model.getName())
.description(model.getDescription())
.dataType(model.getDataType())
.targetType(model.getTargetType())
.targetSubType(model.getTargetSubType())
.targetId(model.getTargetId())
.categoryCode(model.getCategoryCode())
.categoryName(model.getCategoryName())
.ownedFlag(model.getOwnedFlag())
.shareStatus(model.getShareStatus())
.useStatus(model.getUseStatus())
.publishTime(model.getPublishTime())
.offlineTime(model.getOfflineTime())
.versionNumber(model.getVersionNumber())
.author(model.getAuthor())
.publishDoc(model.getPublishDoc())
.configParamJson(model.getConfigParamJson())
.localConfigParamJson(model.getConfigParamJson())
.serverConfigParamJson(null)
.configJson(model.getConfigJson())
.icon(model.getIcon())
.tenantId(model.getTenantId())
.createClientId(model.getCreateClientId())
.created(model.getCreated())
.creatorId(model.getCreatorId())
.creatorName(model.getCreatorName())
.modified(model.getModified())
.modifiedId(model.getModifiedId())
.modifiedName(model.getModifiedName())
.isNewVersion(false)
.serverVersionNumber(null)
.build();
return ecoMarketClientConfigModel;
}
/**
* 将服务器配置详情转换为客户端配置模型
*
* @param serverData 服务器配置详情
* @param tenantId 租户ID
* @return 客户端配置模型
*/
public static EcoMarketClientConfigModel serverDetailToClientConfig(ServerConfigDetailRespDTO serverData,
Long tenantId) {
if (serverData == null) {
return null;
}
EcoMarketClientConfigModel ecoMarketClientConfigModel = EcoMarketClientConfigModel.builder()
.id(serverData.getId())
.uid(serverData.getUid())
.name(serverData.getName())
.description(serverData.getDescription())
.dataType(serverData.getDataType())
.targetType(serverData.getTargetType())
.targetSubType(serverData.getTargetSubType())
.targetId(serverData.getTargetId())
.categoryCode(serverData.getCategoryCode())
.categoryName(serverData.getCategoryName())
.ownedFlag(serverData.getOwnedFlag())
.shareStatus(serverData.getShareStatus())
.useStatus(serverData.getUseStatus())
.publishTime(serverData.getPublishTime())
.offlineTime(serverData.getOfflineTime())
.versionNumber(serverData.getVersionNumber())
.author(serverData.getAuthor())
.publishDoc(serverData.getPublishDoc())
.configParamJson(serverData.getConfigParamJson())
.localConfigParamJson(null)
.configJson(serverData.getConfigJson())
.icon(serverData.getIcon())
// 设置租户ID为空,避免后续客户端使用
.tenantId(null)
.createClientId(serverData.getCreateClientId())
.created(serverData.getCreated())
.creatorId(serverData.getCreatorId())
.creatorName(serverData.getCreatorName())
.modified(serverData.getModified())
.modifiedId(serverData.getModifiedId())
.modifiedName(serverData.getModifiedName())
.isNewVersion(false)
.serverVersionNumber(serverData.getVersionNumber())
.build();
// 设置其他必要字段
ecoMarketClientConfigModel.setShareStatus(serverData.getShareStatus());
ecoMarketClientConfigModel.setUseStatus(EcoMarketUseStatusEnum.DISABLED.getCode());
ecoMarketClientConfigModel.setOwnedFlag(EcoMarketOwnedFlagEnum.NO.getCode()); // 不是自己分享的
return ecoMarketClientConfigModel;
}
/**
* 将服务器配置列表项转换为客户端配置模型
*
* @param serverConfig 服务器配置列表项
* @param tenantId 租户ID
* @return 客户端配置模型
*/
public static EcoMarketClientConfigModel serverListItemToClientConfig(ServerConfigListRespDTO serverConfig,
Long tenantId) {
if (serverConfig == null) {
return null;
}
EcoMarketClientConfigModel newModel = new EcoMarketClientConfigModel();
newModel.setUid(serverConfig.getUid());
newModel.setName(serverConfig.getName());
newModel.setDescription(serverConfig.getDescription());
newModel.setDataType(serverConfig.getDataType());
newModel.setTargetType(serverConfig.getTargetType());
newModel.setTargetSubType(serverConfig.getTargetSubType());
newModel.setTargetId(serverConfig.getTargetId());
newModel.setCategoryCode(serverConfig.getCategoryCode());
newModel.setCategoryName(serverConfig.getCategoryName());
newModel.setShareStatus(serverConfig.getShareStatus());
newModel.setVersionNumber(serverConfig.getVersionNumber());
newModel.setAuthor(serverConfig.getAuthor());
newModel.setPublishDoc(serverConfig.getPublishDoc());
newModel.setIcon(serverConfig.getIcon());
newModel.setOwnedFlag(serverConfig.getOwnedFlag());
newModel.setUseStatus(serverConfig.getUseStatus());
// 新配置无需比较版本
newModel.setIsNewVersion(false);
newModel.setServerVersionNumber(serverConfig.getVersionNumber());
newModel.setTenantId(tenantId);
return newModel;
}
/**
* 比较本地配置与服务器配置的版本
*
* @param clientModel 本地配置
* @param serverModel 服务器配置
*/
public static void compareVersion(EcoMarketClientConfigModel clientModel, EcoMarketClientConfigModel serverModel) {
if (clientModel == null) {
return;
}
boolean isOwnShare = Objects.equals(clientModel.getOwnedFlag(), EcoMarketOwnedFlagEnum.YES.getCode());
if (!isOwnShare) {
// 不是自己分享的,需要与服务器版本比较
if (serverModel != null) {
// 比较版本
if (serverModel.getVersionNumber() > clientModel.getVersionNumber()) {
clientModel.setIsNewVersion(true);
clientModel.setServerVersionNumber(serverModel.getVersionNumber());
} else {
clientModel.setIsNewVersion(false);
clientModel.setServerVersionNumber(serverModel.getVersionNumber());
}
}
} else {
// 设置默认标记(没有新版本)
clientModel.setIsNewVersion(false);
}
}
}

View File

@@ -0,0 +1,57 @@
package com.xspaceagi.eco.market.spec.app.assembler;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientSecret;
import com.xspaceagi.system.spec.enums.YnEnum;
import com.xspaceagi.system.infra.dao.ICommonTranslator;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class EcoMarketClientSecretApplicationTranslator implements ICommonTranslator<ClientSecretDTO, EcoMarketClientSecret> {
@Override
public ClientSecretDTO convertToModel(EcoMarketClientSecret entity) {
if (entity == null) {
return null;
}
ClientSecretDTO clientSecretDTO = ClientSecretDTO.builder()
.id(entity.getId())
.name(entity.getName())
.description(entity.getDescription())
.clientId(entity.getClientId())
.clientSecret(entity.getClientSecret())
.tenantId(entity.getTenantId())
.build();
return clientSecretDTO;
}
@Override
public EcoMarketClientSecret convertToEntity(ClientSecretDTO model) {
if (model == null) {
return null;
}
EcoMarketClientSecret ecoMarketClientSecret = EcoMarketClientSecret.builder()
.id(model.getId())
.name(model.getName())
.description(model.getDescription())
.clientId(model.getClientId())
.clientSecret(model.getClientSecret())
.tenantId(model.getTenantId())
.created(LocalDateTime.now())
.creatorId(null)
.creatorName(null)
.modified(null)
.yn(YnEnum.Y.getKey())
.build();
return ecoMarketClientSecret;
}
}

View File

@@ -0,0 +1,93 @@
package com.xspaceagi.eco.market.spec.app.dto.request;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigQueryRequest;
import com.xspaceagi.eco.market.domain.model.valueobj.QueryEcoMarketVo;
import com.xspaceagi.eco.market.spec.enums.EcoMarketSubTabType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 客户端配置查询请求DTO
*/
@Data
@Schema(description = "客户端配置查询请求DTO")
public class ClientConfigQueryRequest {
/**
* 名称,模糊查询
*/
@Schema(description = "名称,模糊查询")
private String name;
/**
* 市场类型,1:插件;2:模板;3:MCP
*/
@Schema(description = "市场类型,1:插件;2:模板;3:MCP")
@NotNull(message = "Market type is required")
private Integer dataType;
/**
* tab类型: 1: 全部; 2: 启用的;3:我的分享; 默认全部
*
* @see EcoMarketSubTabType
*/
@Schema(description = "tab类型: 1: 全部; 2: 启用的;3:我的分享;")
private Integer subTabType;
/**
* 细分类型,比如: 插件,智能体,工作流
* @see Published.TargetType
*/
@Schema(description = "类型,比如: 插件,智能体,工作流")
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
@Schema(description = "子类型")
private String targetSubType;
/**
* 分类编码
*/
@Schema(description = "分类编码")
private String categoryCode;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
@Schema(description = "分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回")
private Integer shareStatus;
public static QueryEcoMarketVo convertToQueryEcoMarketVo(ClientConfigQueryRequest request) {
return QueryEcoMarketVo.builder()
.name(request.getName())
.dataType(request.getDataType())
.targetType(request.getTargetType())
.targetSubType(request.getTargetSubType())
.subTabType(request.getSubTabType())
.categoryCode(request.getCategoryCode())
.shareStatus(request.getShareStatus())
.useStatus(null)
.ownedFlag(null)
.build();
}
public static ServerConfigQueryRequest convertToServerConfigQueryRequest(ClientConfigQueryRequest request, Integer subTabType) {
ServerConfigQueryRequest serverConfigQueryRequest = new ServerConfigQueryRequest();
serverConfigQueryRequest.setName(request.getName());
serverConfigQueryRequest.setTargetType(request.getTargetType());
serverConfigQueryRequest.setTargetSubType(request.getTargetSubType());
serverConfigQueryRequest.setDataType(request.getDataType());
serverConfigQueryRequest.setSubTabType(subTabType);
serverConfigQueryRequest.setCategoryCode(request.getCategoryCode());
serverConfigQueryRequest.setShareStatus(request.getShareStatus());
return serverConfigQueryRequest;
}
}

View File

@@ -0,0 +1,130 @@
package com.xspaceagi.eco.market.spec.app.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.eco.market.spec.app.dto.request.ClientConfigQueryRequest;
import com.xspaceagi.system.spec.common.UserContext;
import java.util.List;
public interface IEcoMarketClientConfigApplicationService {
/**
* 配置详情
*
* @param id 配置id
*/
EcoMarketClientConfigModel queryOneInfoById(Long id);
/**
* 批量根据ids查询配置
*
* @param ids id列表
* @return 配置列表
*/
List<EcoMarketClientConfigModel> queryListByIds(List<Long> ids);
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 分页查询客户端配置,并与服务器配置比较
*
* @param request 查询参数
* @param current 当前页
* @param size 每页大小
* @param spaceIds 空间ID列表
* @return 分页结果
*/
IPage<EcoMarketClientConfigModel> pageQueryWithServerCompare(ClientConfigQueryRequest request, long current, long size, ClientSecretDTO clientSecret, UserContext userContext);
/**
* 根据uid查询客户端配置
*
* @param uid 唯一ID
* @return 客户端配置
*/
EcoMarketClientConfigModel queryOneByUid(String uid);
/**
* 根据uid列表查询客户端配置
*
* @param uids 唯一ID列表
* @return 客户端配置列表
*/
List<EcoMarketClientConfigModel> queryListByUids(List<String> uids);
/**
* 获取配置详情(包含服务器比对逻辑)
*
* @param uid 配置唯一标识
* @param tenantId 租户ID
* @return 客户端配置,包含是否有新版本的标记
*/
EcoMarketClientConfigModel getConfigDetail(String uid, UserContext userContext);
/**
* 保存并发布配置
*
* @param reqDTO 请求DTO
* @param userContext 用户上下文
* @return 配置模型
*/
EcoMarketClientConfigModel saveAndPublish(EcoMarketClientConfigModel model, String clientId, String clientSecret, UserContext userContext);
/**
* 根据uid下线配置
*
* @param uid 配置UID
* @param userContext 用户上下文
* @return 下线后的配置模型
*/
EcoMarketClientConfigModel offlineConfigByUid(String uid, ClientSecretDTO clientSecret,UserContext userContext);
/**
* 根据uid,撤销发布
*
* @param uid 配置UID
* @param userContext 用户上下文
* @return 下线后的配置模型
*/
void unpublishConfigByUid(String uid, ClientSecretDTO clientSecret,UserContext userContext);
/**
* 根据uid删除配置包含业务检查
*
* @param uid 配置UID
* @param userContext 用户上下文
* @return 是否删除成功
*/
boolean deleteConfigByUid(String uid,ClientSecretDTO clientSecret , UserContext userContext);
/**
* 更新草稿配置
*
* @param model 配置模型
* @param userContext 用户上下文
* @return 更新后的配置模型
*/
EcoMarketClientConfigModel updateDraft(EcoMarketClientConfigModel model, UserContext userContext);
/**
* 创建草稿配置
*
* @param model 配置模型
* @param clientId 客户端ID
* @param userContext 用户上下文
* @return 创建后的配置模型
*/
EcoMarketClientConfigModel saveDraft(EcoMarketClientConfigModel model, String clientId, UserContext userContext);
}

View File

@@ -0,0 +1,79 @@
package com.xspaceagi.eco.market.spec.app.service;
import java.util.List;
import java.util.Map;
import com.xspaceagi.eco.market.domain.dto.req.UpdateAndEnableConfigReqDTO;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.system.spec.common.UserContext;
public interface IEcoMarketClientPublishConfigApplicationService {
/**
* 已发布配置详情
*
* @param id 配置id
*/
EcoMarketClientPublishConfigModel queryOneInfoById(Long id);
/**
* 根据uid查询已发布配置详情
*
* @param uid 配置唯一标识
* @return 已发布配置详情
*/
EcoMarketClientPublishConfigModel queryOneByUid(String uid);
/**
* 批量根据ids查询已发布配置
*
* @param ids id列表
* @return 已发布配置列表
*/
List<EcoMarketClientPublishConfigModel> queryListByIds(List<Long> ids);
/**
* 批量根据uids查询已发布配置
*
* @param uids uid列表
* @return 已发布配置列表
*/
List<EcoMarketClientPublishConfigModel> queryListByUids(List<String> uids);
/**
* 根据参数查询已发布配置列表
*
* @param params 查询参数
* @return 已发布配置列表
*/
List<EcoMarketClientPublishConfigModel> queryListByParams(Map<String, Object> params);
/**
* 启用配置
*
* @param uid 配置唯一标识
* @param userContext 用户上下文
* @return 启用后的配置模型
*/
EcoMarketClientPublishConfigModel enableConfig(String uid, UserContext userContext);
/**
* 禁用配置
*
* @param uid 配置唯一标识
* @param userContext 用户上下文
* @return 禁用后的配置模型
*/
EcoMarketClientPublishConfigModel disableConfig(String uid, UserContext userContext);
/**
* 更新并启用配置
*
* @param request 更新配置
* @param userContext 用户上下文
* @return 启用后的配置模型
*/
EcoMarketClientPublishConfigModel updateAndEnableConfig(UpdateAndEnableConfigReqDTO request, UserContext userContext);
}

View File

@@ -0,0 +1,64 @@
package com.xspaceagi.eco.market.spec.app.service;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientSecretModel;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.system.spec.common.UserContext;
import java.util.List;
public interface IEcoMarketClientSecretApplicationService {
/**
* 客户端密钥详情
*
* @param id 密钥id
*/
EcoMarketClientSecretModel queryOneInfoById(Long id);
/**
* 批量根据ids查询客户端密钥
*
* @param ids id列表
* @return 客户端密钥列表
*/
List<EcoMarketClientSecretModel> queryListByIds(List<Long> ids);
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 更新
*
* @param model 模型
* @return id
*/
Long updateInfo(EcoMarketClientSecretModel model, UserContext userContext);
/**
* 新增
*/
Long addInfo(EcoMarketClientSecretModel model, UserContext userContext);
/**
* 保存客户端密钥DTO
*
* @param clientSecretDTO 客户端密钥DTO
* @param userContext 用户上下文
* @return 密钥ID
*/
Long saveClientSecretDTO(ClientSecretDTO clientSecretDTO, UserContext userContext);
/**
* 检查租户是否已有客户端密钥
*
* @param tenantId 租户ID
* @return 是否存在
*/
boolean existsClientSecret(Long tenantId);
}

View File

@@ -0,0 +1,855 @@
package com.xspaceagi.eco.market.spec.app.service.impl;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.xspaceagi.custompage.sdk.ICustomPageRpcService;
import com.xspaceagi.custompage.sdk.dto.CustomPageDto;
import org.springframework.stereotype.Service;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xspaceagi.agent.core.adapter.repository.AgentComponentConfigRepository;
import com.xspaceagi.agent.core.adapter.repository.entity.AgentComponentConfig;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import com.xspaceagi.custompage.application.service.ICustomPageConfigApplicationService;
import com.xspaceagi.eco.market.domain.client.EcoMarketServerApiService;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigQueryRequest;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigSaveReqDTO;
import com.xspaceagi.eco.market.domain.dto.resp.ServerConfigDetailRespDTO;
import com.xspaceagi.eco.market.domain.dto.resp.ServerConfigListRespDTO;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientConfigDomainService;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientPublishConfigDomainService;
import com.xspaceagi.eco.market.domain.specification.EcoMarkerSecretWrapper;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.eco.market.spec.app.assembler.EcoMarketClientConfigTranslator;
import com.xspaceagi.eco.market.spec.app.dto.request.ClientConfigQueryRequest;
import com.xspaceagi.eco.market.spec.app.service.IEcoMarketClientConfigApplicationService;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketOwnedFlagEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketShareStatusEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketSubTabType;
import com.xspaceagi.eco.market.spec.enums.EcoMarketUseStatusEnum;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.dto.ReqResult;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import com.xspaceagi.system.spec.page.PageQueryVo;
import com.xspaceagi.system.spec.page.SuperPage;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class EcoMarketClientConfigApplicationService implements IEcoMarketClientConfigApplicationService {
@Resource
private IEcoMarketClientConfigDomainService ecoMarketClientConfigDomainService;
@Resource
private EcoMarketServerApiService ecoMarketServerApiService;
@Resource
private IEcoMarketClientPublishConfigDomainService ecoMarketClientPublishConfigDomainService;
@Resource
private EcoMarkerSecretWrapper ecoMarkerSecretWrapper;
@Resource
private AgentComponentConfigRepository agentComponentConfigRepository;
@Resource
private ICustomPageConfigApplicationService customPageConfigApplicationService;
@Resource
private ICustomPageRpcService iCustomPageRpcService;
@Override
public EcoMarketClientConfigModel queryOneInfoById(Long id) {
return ecoMarketClientConfigDomainService.queryOneInfoById(id);
}
@Override
public List<EcoMarketClientConfigModel> queryListByIds(List<Long> ids) {
return ecoMarketClientConfigDomainService.queryListByIds(ids);
}
@Override
public void deleteById(Long id) {
ecoMarketClientConfigDomainService.deleteById(id);
}
@Override
public IPage<EcoMarketClientConfigModel> pageQueryWithServerCompare(ClientConfigQueryRequest request, long current,
long size, ClientSecretDTO clientSecret, UserContext userContext) {
// 获取客户端凭证
if (clientSecret == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketClientSecretFetchFailed);
}
IPage<EcoMarketClientConfigModel> result;
// 获取tab类型
var subTabType = EcoMarketSubTabType.getByCode(request.getSubTabType());
if (subTabType == null) {
request.setSubTabType(EcoMarketSubTabType.ALL.getCode());
subTabType = EcoMarketSubTabType.ALL;
}
var queryEcoMarketVo = ClientConfigQueryRequest.convertToQueryEcoMarketVo(request);
// 根据tab类型执行不同查询策略
switch (subTabType) {
case ALL -> {
// 对于"ALL"类型,通过HTTP请求服务器端list接口获取所有配置
log.info("Query all configs: subTabType={}", subTabType.getCode());
// 创建请求DTO
PageQueryVo<ServerConfigQueryRequest> listReqDTO = new PageQueryVo<>();
// 设置分页参数
listReqDTO.setCurrent(current);
listReqDTO.setPageSize(size);
// 设置查询条件
ServerConfigQueryRequest queryFilter = ClientConfigQueryRequest.convertToServerConfigQueryRequest(
request,
subTabType.getCode());
listReqDTO.setQueryFilter(queryFilter);
// 调用服务器端查询接口
SuperPage<ServerConfigListRespDTO> serverPage = ecoMarketServerApiService
.queryServerConfigList(listReqDTO);
if (serverPage == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed, "从服务器查询配置列表失败");
}
// 处理服务器返回的数据
List<ServerConfigListRespDTO> serverRecords = serverPage.getRecords();
if (serverRecords.isEmpty()) {
// 服务器没有数据,返回空结果
SuperPage<EcoMarketClientConfigModel> emptyPage = new SuperPage<>();
emptyPage.setCurrent(current);
emptyPage.setSize(size);
emptyPage.setTotal(serverPage.getTotal());
emptyPage.setRecords(Collections.emptyList());
return emptyPage;
}
// 提取服务器端配置的UID列表
List<String> serverUids = serverRecords.stream()
.map(ServerConfigListRespDTO::getUid)
.collect(Collectors.toList());
// 在本地查询这些UID对应的配置
List<EcoMarketClientConfigModel> localConfigs = ecoMarketClientConfigDomainService
.queryListByUids(serverUids);
// 查询本地启用的配置
List<EcoMarketClientPublishConfigModel> enabledConfigs = ecoMarketClientPublishConfigDomainService
.queryListByUids(serverUids);
// 构建UID到本地配置的映射
Map<String, EcoMarketClientConfigModel> localConfigMap = localConfigs.stream()
.collect(Collectors.toMap(
EcoMarketClientConfigModel::getUid,
config -> config,
(existing, replacement) -> existing));
// 构建UID到本地配置的映射
Map<String, EcoMarketClientPublishConfigModel> enabledConfigMap = enabledConfigs.stream()
.filter(config -> config.getUseStatus() == EcoMarketUseStatusEnum.ENABLED.getCode())
.collect(Collectors.toMap(
EcoMarketClientPublishConfigModel::getUid,
config -> config,
(existing, replacement) -> existing));
// 将服务器数据转换为本地模型,并与本地数据比较版本
var page = serverPage.convert(serverConfig -> {
EcoMarketClientConfigModel newModel = EcoMarketClientConfigTranslator
.serverListItemToClientConfig(serverConfig, clientSecret.getTenantId());
// serverConfig 服务器的初始为:未启用,后续根据本地数据的情况,来修改启用状态
newModel.setUseStatus(EcoMarketUseStatusEnum.DISABLED.getCode());
// 设置为非自己分享
newModel.setOwnedFlag(EcoMarketOwnedFlagEnum.NO.getCode());
// 默认没有新版本
newModel.setIsNewVersion(false);
newModel.setServerVersionNumber(serverConfig.getVersionNumber());
var localConfig = localConfigMap.get(serverConfig.getUid());
var enabledConfig = enabledConfigMap.get(serverConfig.getUid());
if (localConfig != null) {
// 根据 localConfig 设置 是否我的分享标记
if (localConfig.getOwnedFlag() == EcoMarketOwnedFlagEnum.YES.getCode()) {
newModel.setOwnedFlag(EcoMarketOwnedFlagEnum.YES.getCode());
}
}
// 检查启用状态
if (enabledConfig != null) {
newModel.setUseStatus(enabledConfig.getUseStatus());
// 本地存在,比较版本
if (serverConfig.getVersionNumber() > enabledConfig.getVersionNumber()) {
// 服务器有新版本
newModel.setIsNewVersion(true);
newModel.setServerVersionNumber(serverConfig.getVersionNumber());
}
} else {
// 如果本地不存在启用配置,则设置为禁用
newModel.setUseStatus(EcoMarketUseStatusEnum.DISABLED.getCode());
}
return newModel;
});
result = page;
break;
}
case ENABLED -> {
// 对于"ENABLED"类型,查询本地已启用配置表
log.info("Query enabled configs: subTabType={}, dataType={}", subTabType.getCode(), request.getDataType());
// 直接使用领域服务的分页查询启用状态的配置方法
IPage<EcoMarketClientPublishConfigModel> clientPage = ecoMarketClientPublishConfigDomainService
.pageQueryEnabled(queryEcoMarketVo, current, size);
IPage<EcoMarketClientConfigModel> clientLocalConfigs = clientPage
.convert(EcoMarketClientPublishConfigModel::toClientConfigModel);
if (clientLocalConfigs.getRecords().isEmpty()) {
// 没有已启用配置,返回空结果
return clientLocalConfigs;
}
// 获取所有记录的uid列表
List<String> configUids = clientLocalConfigs.getRecords().stream()
.map(EcoMarketClientConfigModel::getUid)
.toList();
// 从服务器获取最新版本信息
try {
// 使用批量获取服务器配置审批详情接口
List<ServerConfigDetailRespDTO> serverConfigDetails = ecoMarketServerApiService
.getBatchServerConfigDetail(
configUids,
clientSecret.getClientId(),
clientSecret.getClientSecret());
if (serverConfigDetails != null && !serverConfigDetails.isEmpty()) {
// 构建UID到服务器配置的映射
Map<String, ServerConfigDetailRespDTO> serverConfigMap = serverConfigDetails.stream()
.collect(Collectors.toMap(
ServerConfigDetailRespDTO::getUid,
config -> config,
(existing, replacement) -> existing));
// 比较版本并更新本地配置信息
for (EcoMarketClientConfigModel clientConfig : clientLocalConfigs.getRecords()) {
ServerConfigDetailRespDTO serverConfig = serverConfigMap.get(clientConfig.getUid());
if (serverConfig != null && serverConfig.getVersionNumber() != null) {
// 比较版本
if (serverConfig.getVersionNumber() > clientConfig.getVersionNumber()) {
// 服务器有新版本
clientConfig.setIsNewVersion(true);
clientConfig.setServerVersionNumber(serverConfig.getVersionNumber());
} else {
// 本地版本是最新的
clientConfig.setIsNewVersion(false);
clientConfig.setServerVersionNumber(serverConfig.getVersionNumber());
}
}
}
}
} catch (Exception e) {
log.error("Failed to get server config detail", e);
// 即使获取服务器配置失败,仍然返回本地数据
}
// 由于我们已经使用了分页查询,直接返回结果即可
result = clientLocalConfigs;
break;
}
case MY_SHARE -> {
// 对于"MY_SHARE"类型,查询本地我分享的配置
log.info("Query my shares: subTabType={}", subTabType.getCode());
// 检查待审批的数据,进行更新我的分享状态
updateApproveShareStatus(clientSecret, userContext);
// 直接调用领域服务查询
var clientLocalConfigs = ecoMarketClientConfigDomainService.pageQueryMyShare(queryEcoMarketVo, current,
size);
// 查询服务器,获取其审批状态
if (clientLocalConfigs.getRecords().isEmpty()) {
// 没有已启用配置,返回空结果
return clientLocalConfigs;
}
// 获取所有记录的uid列表
List<String> configUids = clientLocalConfigs.getRecords().stream()
.map(EcoMarketClientConfigModel::getUid)
.collect(Collectors.toList());
// 从服务器获取最新版本信息
try {
// 使用批量获取服务器配置详情接口
List<ServerConfigDetailRespDTO> serverConfigDetails = ecoMarketServerApiService
.getBatchServerApproveDetail(
configUids,
clientSecret.getClientId(),
clientSecret.getClientSecret());
if (serverConfigDetails != null && !serverConfigDetails.isEmpty()) {
// 构建UID到服务器配置的映射
Map<String, ServerConfigDetailRespDTO> serverConfigMap = serverConfigDetails.stream()
.collect(Collectors.toMap(
ServerConfigDetailRespDTO::getUid,
config -> config,
(existing, replacement) -> existing));
// 比较版本并更新本地配置信息
for (EcoMarketClientConfigModel clientConfig : clientLocalConfigs.getRecords()) {
ServerConfigDetailRespDTO serverConfig = serverConfigMap.get(clientConfig.getUid());
if (serverConfig != null && serverConfig.getVersionNumber() != null) {
// 获取审批状态
var shareStatus = serverConfig.getShareStatus();
var approveMessage = serverConfig.getApproveMessage();
var uid = clientConfig.getUid();
var clientShareStatus = clientConfig.getShareStatus();
// 如果server端的状态,和本地状态不一样,也进行更新,可能server端操作了下架动作
if (!Objects.equals(shareStatus, clientShareStatus)) {
try {
log.info("Update local config share status, uid:{}, shareStatus:{}",
clientConfig.getUid(), shareStatus);
ecoMarketClientConfigDomainService.updateShareStatusByUid(
clientConfig.getUid(),
shareStatus, approveMessage, userContext);
} catch (Exception e) {
log.error("Update local share status failed, uid:{}, shareStatus:{}",
clientConfig.getUid(), shareStatus, e);
}
}
// 设置分享状态
clientConfig.setShareStatus(shareStatus);
clientConfig.setApproveMessage(approveMessage);
}
}
}
} catch (Exception e) {
log.error("Failed to get server config detail", e);
// 即使获取服务器配置失败,仍然返回本地数据
}
result = clientLocalConfigs;
break;
}
default -> {
throw new UnsupportedOperationException("不支持的tab类型: " + subTabType.getCode());
}
}
if (!result.getRecords().isEmpty()) {
// 查询页面封面
List<Long> agentIds = result.getRecords().stream()
.filter(c -> Published.TargetType.Agent.name().equals(c.getTargetType())
&& Published.TargetSubType.PageApp.name().equals(c.getTargetSubType()))
.map(EcoMarketClientConfigModel::getTargetId).toList();
if (!agentIds.isEmpty()) {
List<CustomPageDto> pageDtos = iCustomPageRpcService.listByAgentIds(agentIds);
Map<Long, CustomPageDto> pageDtoMap = pageDtos.stream()
.filter(dto -> dto.getDevAgentId() != null)
.collect(Collectors.toMap(
CustomPageDto::getDevAgentId,
dto -> dto,
(v1, v2) -> v1 // 如果有重复,保留第一个
));
for (EcoMarketClientConfigModel config : result.getRecords()) {
CustomPageDto pageDto = pageDtoMap.get(config.getTargetId());
if (pageDto != null) {
config.setCoverImg(pageDto.getCoverImg());
config.setCoverImgSourceType(pageDto.getCoverImgSourceType());
}
}
}
}
return result;
}
/**
* 检查待审核的状态的数据,获取最新状态并更新
*
* @param clientSecret
* @param userContext
*/
private void updateApproveShareStatus(ClientSecretDTO clientSecret, UserContext userContext) {
// 先查询审批中的数据,调用远程服务器,然后更新审批状态到本地
var myShareAndReviewing = ecoMarketClientConfigDomainService.queryMyShareAndReviewing();
if (!myShareAndReviewing.isEmpty()) {
log.info("Found pending-approval configs, updating approval status, count:{}", myShareAndReviewing.size());
try {
// 获取所有记录的uid列表
List<String> configUids = myShareAndReviewing.stream()
.map(EcoMarketClientConfigModel::getUid)
.collect(Collectors.toList());
// 从服务器获取最新版本信息
List<ServerConfigDetailRespDTO> serverConfigDetails = ecoMarketServerApiService
.getBatchServerApproveDetail(
configUids,
clientSecret.getClientId(),
clientSecret.getClientSecret());
if (serverConfigDetails != null && !serverConfigDetails.isEmpty()) {
// 构建UID到服务器配置的映射
Map<String, ServerConfigDetailRespDTO> serverConfigMap = serverConfigDetails.stream()
.collect(Collectors.toMap(
ServerConfigDetailRespDTO::getUid,
config -> config,
(existing, replacement) -> existing));
// 比较版本并更新本地配置信息
for (EcoMarketClientConfigModel clientConfig : myShareAndReviewing) {
ServerConfigDetailRespDTO serverConfig = serverConfigMap.get(clientConfig.getUid());
if (serverConfig != null && serverConfig.getVersionNumber() != null) {
// 获取审批状态
var shareStatus = serverConfig.getShareStatus();
var approveMessage = serverConfig.getApproveMessage();
// 如果server端的审批状态不是 审批中 状态,则更新状态
if (!EcoMarketShareStatusEnum.REVIEWING.getCode().equals(shareStatus)) {
try {
log.info("Update local approval status, uid:{}, shareStatus:{}",
clientConfig.getUid(), shareStatus);
ecoMarketClientConfigDomainService.updateShareStatusByUid(
clientConfig.getUid(),
shareStatus, approveMessage, userContext);
} catch (Exception e) {
log.error("Update local approval status failed, uid:{}, shareStatus:{}",
clientConfig.getUid(), shareStatus, e);
}
}
}
}
}
} catch (Exception e) {
log.error("Get server config approval status failed", e);
}
}
}
@Override
public EcoMarketClientConfigModel queryOneByUid(String uid) {
return ecoMarketClientConfigDomainService.queryOneByUid(uid);
}
@Override
public List<EcoMarketClientConfigModel> queryListByUids(List<String> uids) {
return ecoMarketClientConfigDomainService.queryListByUids(uids);
}
@Override
public EcoMarketClientConfigModel getConfigDetail(String uid, UserContext userContext) {
Long tenantId = userContext.getTenantId();
log.info("Get config detail: uid={}, tenantId={}", uid, tenantId);
// 先查询本地是否存在该uid的配置
EcoMarketClientConfigModel clientConfigModel = ecoMarketClientConfigDomainService.queryOneByUid(uid);
// 查询publish_config 表,是否存在该uid的配置
EcoMarketClientPublishConfigModel publishConfigModel = ecoMarketClientPublishConfigDomainService
.queryOneByUid(uid);
// 获取服务端的配置详情
EcoMarketClientConfigModel serverConfigModel = fetchConfigFromServer(uid, tenantId);
// 如果本地和服务器都没有找到配置
if (publishConfigModel == null && serverConfigModel == null && clientConfigModel == null) {
log.warn("Config not found: uid={}", uid);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
// 首先判断这个uid对应的配置,是否是我的创建分享的配置
var ownedFlag = false;
if (Objects.nonNull(clientConfigModel)) {
ownedFlag = Objects.equals(clientConfigModel.getOwnedFlag(), EcoMarketOwnedFlagEnum.YES.getCode());
if (!ownedFlag) {
// 不是我创建分享的配置,则使用publish配置
if (Objects.nonNull(publishConfigModel)) {
clientConfigModel = EcoMarketClientConfigTranslator.toClientConfigModel(publishConfigModel);
}
clientConfigModel.setOwnedFlag(EcoMarketOwnedFlagEnum.NO.getCode());
} else {
clientConfigModel.setOwnedFlag(EcoMarketOwnedFlagEnum.YES.getCode());
}
// 比较版本
EcoMarketClientConfigTranslator.compareVersion(clientConfigModel, serverConfigModel);
// 设置本地 LocalConfigParamJson
clientConfigModel.setLocalConfigParamJson(clientConfigModel.getConfigParamJson());
// 设置本地 ServerConfigJson
clientConfigModel.setLocalConfigJson(clientConfigModel.getConfigJson());
// 设置服务器配置参数json
if (Objects.nonNull(serverConfigModel)) {
clientConfigModel.setServerConfigParamJson(serverConfigModel.getConfigParamJson());
// mcp 需要使用这个 configJSON
clientConfigModel.setServerConfigJson(serverConfigModel.getConfigJson());
}
return clientConfigModel;
} else {
// 如果本地不存在但服务器存在,使用服务器配置
if (Objects.nonNull(serverConfigModel)) {
serverConfigModel.setServerConfigParamJson(serverConfigModel.getConfigParamJson());
serverConfigModel.setServerConfigJson(serverConfigModel.getConfigJson());
serverConfigModel.setOwnedFlag(EcoMarketOwnedFlagEnum.NO.getCode());
serverConfigModel.setTenantId(null);
serverConfigModel.setUseStatus(EcoMarketUseStatusEnum.DISABLED.getCode());
}
return serverConfigModel;
}
}
/**
* 从服务器获取配置
*
* @param uid 配置唯一标识
* @param tenantId 租户ID
* @return 配置信息
*/
private EcoMarketClientConfigModel fetchConfigFromServer(String uid, Long tenantId) {
// 获取客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(tenantId);
if (clientSecret == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketClientSecretFetchFailed, "获取客户端密钥失败");
}
// 直接调用ServerApiService的getDetailByUid方法获取数据
ServerConfigDetailRespDTO serverData = ecoMarketServerApiService.getServerConfigDetail(
uid, clientSecret.getClientId(), clientSecret.getClientSecret());
if (serverData == null) {
return null;
}
// 使用转换器将服务器配置转换为客户端配置模型
return EcoMarketClientConfigTranslator.serverDetailToClientConfig(serverData, tenantId);
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public EcoMarketClientConfigModel saveAndPublish(EcoMarketClientConfigModel model, String clientId,
String clientSecret, UserContext userContext) {
// 检查参数
if (Objects.isNull(model)) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置模型");
}
log.info("Save and publish config: clientId={}, name={}", clientId, model.getName());
// 根据 targetId,targetType,进行重复检查,相同的插件/模板,不允许重复创建分享发布
var targetId = model.getTargetId();
var targetType = model.getTargetType();
var targetSubType = model.getTargetSubType();
var dataTypeEnum = EcoMarketDataTypeEnum.getByCode(model.getDataType());
String uid = model.getUid();
if (Published.TargetType.Agent.name().equals(targetType)) {
if (targetSubType == null
|| Stream.of(Published.TargetSubType.ChatBot, Published.TargetSubType.PageApp, Published.TargetSubType.TaskAgent).noneMatch(t -> t.name().equals(targetSubType))) {
throw new EcoMarketException("8000", "targetSubType不能为空");
}
}
// 检查配置是否重复(排除自身uid)
var isRepeat = ecoMarketClientConfigDomainService.checkConfigRepeat(targetId, targetType, dataTypeEnum, uid);
if (isRepeat) {
var dataType = Optional.ofNullable(dataTypeEnum).map(EcoMarketDataTypeEnum::getCode).orElse(null);
log.warn("Duplicate config: targetId={}, targetType={}, dataType={}", targetId, targetType, dataType);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketDuplicateShareNotAllowed);
}
// 再 ecoMarketClientPublishConfig 表里的,都是从生态市场里获取到的,禁止重复分享
var isPublishRepeat = ecoMarketClientPublishConfigDomainService.checkConfigRepeat(targetId, targetType,
dataTypeEnum);
if (isPublishRepeat) {
var dataType = Optional.ofNullable(dataTypeEnum).map(EcoMarketDataTypeEnum::getCode).orElse(null);
log.warn("Sharing eco-market fetched config is forbidden: targetId={}, targetType={}, dataType={}", targetId, targetType, dataType);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketCannotShareFromMarket);
}
// 获取配置json
var configJson = ecoMarketClientConfigDomainService.obtainConfigJson(dataTypeEnum, model.getTargetId(),
model.getTargetType(), model.getConfigParamJson());
model.setConfigJson(configJson);
// 应用页面
if (Published.TargetType.Agent.name().equals(targetType) && Published.TargetSubType.PageApp.name().equals(targetSubType)) {
String pageZipUrl = uploadPageZip(targetId, clientId, clientSecret, userContext);
model.setPageZipUrl(pageZipUrl);
}
// 设置基本属性
model.setShareStatus(EcoMarketShareStatusEnum.REVIEWING.getCode()); // 初始设置为审核中状态
model.setCreateClientId(clientId); // 使用注册的客户端ID
model.setOwnedFlag(EcoMarketOwnedFlagEnum.YES.getCode()); // 我的分享
model.setUseStatus(EcoMarketUseStatusEnum.DISABLED.getCode()); // 启用状态
// 先在本地保存
if (Objects.isNull(uid)) {
// 新增操作,生成新的uid
uid = UUID.randomUUID().toString().replace("-", "");
model.setUid(uid);
// 新增配置
ecoMarketClientConfigDomainService.addInfo(model, userContext);
} else {
// 更新配置
ecoMarketClientConfigDomainService.updateInfoByUid(model, userContext);
}
// 重新查询最新数据
model = ecoMarketClientConfigDomainService.queryOneByUid(uid);
if (model == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "配置保存失败");
}
// 构建请求DTO并调用服务器端接口
ServerConfigSaveReqDTO reqDTO = EcoMarketClientConfigTranslator.toServerConfigSaveReqDTO(model, clientId,
clientSecret);
ServerConfigDetailRespDTO serverResponse = ecoMarketServerApiService.saveAndPublishServerConfig(reqDTO,
ServerConfigDetailRespDTO.class);
// 服务器端操作成功,更新本地状态
if (serverResponse != null) {
// 更新本地配置状态为审核中,发布时间和版本号
model.setPublishTime(LocalDateTime.now());
model.setVersionNumber(serverResponse.getVersionNumber()); // 使用服务器返回的版本号
// 更新本地数据库
ecoMarketClientConfigDomainService.updateInfoByUid(model, userContext);
log.info("Publish config row updated: uid={}", uid);
// 返回更新后的配置
return ecoMarketClientConfigDomainService.queryOneByUid(uid);
}
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishConfigFailed, "保存并发布配置失败");
}
// 上传页面项目到生态市场server端
private String uploadPageZip(Long agentId, String clientId, String clientSecret, UserContext userContext) {
AgentComponentConfig config = agentComponentConfigRepository.getOne(Wrappers.<AgentComponentConfig>lambdaQuery()
.eq(AgentComponentConfig::getAgentId, agentId)
.eq(AgentComponentConfig::getType, AgentComponentConfig.Type.Page));
if (Objects.isNull(config)) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketAgentPageRequiredForShare);
}
Long pageId = config.getTargetId();
ReqResult<InputStream> result = customPageConfigApplicationService.exportProjectPublished(pageId, userContext);
if (!result.isSuccess()) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageExportFailed);
}
InputStream inputStream = result.getData();
if (inputStream == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageExportFailed);
}
try {
byte[] bytes = inputStream.readAllBytes();
String fileName = String.format("project_%s.zip", pageId);
String url = ecoMarketServerApiService.uploadPageZip(bytes, fileName, "application/zip", clientId, clientSecret);
if (url == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageExportFailed, "上传文件到服务器端失败");
}
return url;
} catch (IOException e) {
log.error("Upload page zip failed: agentId={}, pageId={}", agentId, pageId, e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageExportFailed, "读取文件流失败");
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
log.warn("Failed to close input stream", e);
}
}
}
@Override
@DSTransactional(rollbackFor = Exception.class)
public boolean deleteConfigByUid(String uid, ClientSecretDTO clientSecret, UserContext userContext) {
log.info("Delete client config by uid: uid={}", uid);
// 根据uid查询配置详情
EcoMarketClientConfigModel configModel = queryOneByUid(uid);
if (configModel == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
// 限制是我的分享,是否我的分享,0:否(生态市场获取的);1:是(我的分享)
if (Objects.equals(configModel.getOwnedFlag(), EcoMarketOwnedFlagEnum.NO.getCode())) {
log.warn("Cannot delete eco-market-fetched config: uid={}, ownedFlag={}", uid, configModel.getOwnedFlag());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketDeleteOnlyOwnShare);
}
// 直接调用ServerApiService的getDetailByUid方法获取数据
ServerConfigDetailRespDTO serverData = ecoMarketServerApiService.getServerConfigDetail(
uid, clientSecret.getClientId(), clientSecret.getClientSecret());
// 远程生态市场有上架的对应配置,禁止删除我的分享
if (Objects.nonNull(serverData) && Objects.equals(serverData.getShareStatus(), EcoMarketShareStatusEnum.PUBLISHED.getCode())) {
log.warn("Cannot delete remote published config: uid={}, useStatus={}", uid, serverData.getUseStatus());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketCannotDeleteRemotePublished);
}
// 删除配置
ecoMarketClientConfigDomainService.deleteById(configModel.getId());
return true;
}
@Override
public EcoMarketClientConfigModel offlineConfigByUid(String uid, ClientSecretDTO clientSecret,
UserContext userContext) {
log.info("Offline client config by uid: uid={}", uid);
// 获取客户端密钥
if (clientSecret == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketClientSecretFetchFailed);
}
// 调用领域层下线配置
ecoMarketClientConfigDomainService.offlineConfig(
uid, clientSecret.getClientId(), clientSecret.getClientSecret(), userContext);
// 查询详情并返回
return this.queryOneByUid(uid);
}
@Override
public void unpublishConfigByUid(String uid, ClientSecretDTO clientSecret, UserContext userContext) {
ecoMarketClientConfigDomainService.unpublishConfig(uid, clientSecret.getClientId(),
clientSecret.getClientSecret(), userContext);
}
@Override
@DSTransactional(rollbackFor = Exception.class)
public EcoMarketClientConfigModel updateDraft(EcoMarketClientConfigModel model, UserContext userContext) {
log.info("Update client config draft: uid={}, name={}", model.getUid(), model.getName());
// 参数校验
if (model == null || model.getUid() == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketModelAndUidRequired);
}
// 获取配置json
var dataTypeEnum = EcoMarketDataTypeEnum.getByCode(model.getDataType());
var configJson = ecoMarketClientConfigDomainService.obtainConfigJson(dataTypeEnum, model.getTargetId(),
model.getTargetType(), model.getConfigParamJson());
model.setConfigJson(configJson);
var uid = model.getUid();
// 根据UID查询配置
EcoMarketClientConfigModel existingModel = ecoMarketClientConfigDomainService.queryOneByUid(uid);
if (existingModel == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
// 检查是否为草稿状态
if (existingModel.getShareStatus() != EcoMarketShareStatusEnum.DRAFT.getCode() &&
existingModel.getShareStatus() != EcoMarketShareStatusEnum.REJECTED.getCode()) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketUpdateOnlyDraftOrRejected);
}
// 检查是否有权限更新
if (existingModel.getOwnedFlag() != EcoMarketOwnedFlagEnum.YES.getCode() ||
!userContext.getTenantId().equals(existingModel.getTenantId())) {
throw EcoMarketException.build(BizExceptionCodeEnum.permissionDenied);
}
// 保留原有ID和创建信息
model.setId(existingModel.getId());
model.setCreateClientId(existingModel.getCreateClientId());
model.setCreated(existingModel.getCreated());
model.setCreatorId(existingModel.getCreatorId());
model.setCreatorName(existingModel.getCreatorName());
// 确保是草稿状态
model.setShareStatus(EcoMarketShareStatusEnum.DRAFT.getCode());
// 调用领域服务更新配置
Long id = ecoMarketClientConfigDomainService.updateDraft(model, userContext);
// 查询详情并返回
return queryOneInfoById(id);
}
@Override
@DSTransactional(rollbackFor = Exception.class)
public EcoMarketClientConfigModel saveDraft(EcoMarketClientConfigModel model, String clientId,
UserContext userContext) {
log.info("Create client config draft: name={}", model.getName());
var targetId = model.getTargetId();
var targetType = model.getTargetType();
var dataTypeEnum = EcoMarketDataTypeEnum.getByCode(model.getDataType());
// 再 ecoMarketClientPublishConfig 表里的,都是从生态市场里获取到的,禁止重复分享
var isPublishRepeat = ecoMarketClientPublishConfigDomainService.checkConfigRepeat(targetId, targetType,
dataTypeEnum);
if (isPublishRepeat) {
var dataType = Optional.ofNullable(dataTypeEnum).map(EcoMarketDataTypeEnum::getCode).orElse(null);
log.warn("Sharing eco-market fetched config is forbidden: targetId={}, targetType={}, dataType={}", targetId, targetType, dataType);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketCannotShareFromMarket);
}
// 获取配置json
var configJson = ecoMarketClientConfigDomainService.obtainConfigJson(dataTypeEnum, model.getTargetId(),
model.getTargetType(), model.getConfigParamJson());
model.setConfigJson(configJson);
// 设置基本属性
model.setUid(UUID.randomUUID().toString().replace("-", "")); // 生成UID
model.setVersionNumber(1L); // 初始版本号
model.setShareStatus(EcoMarketShareStatusEnum.DRAFT.getCode()); // 草稿状态
model.setOwnedFlag(EcoMarketOwnedFlagEnum.YES.getCode()); // 我的分享
model.setTenantId(userContext.getTenantId());
model.setCreateClientId(clientId); // 设置客户端ID
model.setUseStatus(EcoMarketUseStatusEnum.ENABLED.getCode());
// 调用领域服务添加配置
Long id = ecoMarketClientConfigDomainService.addInfo(model, userContext);
// 查询详情并返回
return queryOneInfoById(id);
}
}

View File

@@ -0,0 +1,137 @@
package com.xspaceagi.eco.market.spec.app.service.impl;
import java.util.List;
import java.util.Map;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.xspaceagi.eco.market.domain.dto.req.UpdateAndEnableConfigReqDTO;
import org.springframework.stereotype.Service;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientConfigDomainService;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientPublishConfigDomainService;
import com.xspaceagi.eco.market.spec.app.service.IEcoMarketClientPublishConfigApplicationService;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class EcoMarketClientPublishConfigApplicationService implements IEcoMarketClientPublishConfigApplicationService {
@Resource
private IEcoMarketClientPublishConfigDomainService ecoMarketClientPublishConfigDomainService;
@Resource
private IEcoMarketClientConfigDomainService ecoMarketClientConfigDomainService;
@Override
public EcoMarketClientPublishConfigModel queryOneInfoById(Long id) {
return ecoMarketClientPublishConfigDomainService.queryOneInfoById(id);
}
@Override
public List<EcoMarketClientPublishConfigModel> queryListByIds(List<Long> ids) {
return ecoMarketClientPublishConfigDomainService.queryListByIds(ids);
}
@Override
public List<EcoMarketClientPublishConfigModel> queryListByUids(List<String> uids) {
return ecoMarketClientPublishConfigDomainService.queryListByUids(uids);
}
@Override
public EcoMarketClientPublishConfigModel queryOneByUid(String uid) {
log.info("Query client published config by uid: uid={}", uid);
return ecoMarketClientPublishConfigDomainService.queryOneByUid(uid);
}
/**
* 根据参数查询已发布配置列表
*
* @param params 查询参数
* @return 已发布配置列表
*/
public List<EcoMarketClientPublishConfigModel> queryListByParams(Map<String, Object> params) {
log.info("Query published configs: params={}", params);
// 使用根据UID批量查询
if (params != null && params.containsKey("uids")) {
List<String> uids = (List<String>) params.get("uids");
if (uids != null && !uids.isEmpty()) {
// 查询UID对应的记录
return uids.stream()
.map(uid -> ecoMarketClientPublishConfigDomainService.queryOneByUid(uid))
.filter(model -> model != null) // 过滤掉查询不到的记录
.toList();
}
}
// 暂时返回空列表,可以后续扩展为通过仓库层查询
return java.util.Collections.emptyList();
}
/**
* 启用配置
*
* @param uid 配置唯一标识
* @param userContext 用户上下文
* @return 启用后的配置模型
*/
@DSTransactional(rollbackFor = Exception.class)
@Override
public EcoMarketClientPublishConfigModel enableConfig(String uid, UserContext userContext) {
log.info("Application layer: enable config: uid={}", uid);
if (uid == null || uid.isEmpty()) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置UID");
}
// 调用领域服务启用配置
return ecoMarketClientPublishConfigDomainService.enableConfig(uid, userContext);
}
/**
* 禁用配置
*
* @param uid 配置唯一标识
* @param userContext 用户上下文
* @return 禁用后的配置模型
*/
@DSTransactional(rollbackFor = Exception.class)
@Override
public EcoMarketClientPublishConfigModel disableConfig(String uid, UserContext userContext) {
log.info("Application layer: disable config: uid={}", uid);
if (uid == null || uid.isEmpty()) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置UID");
}
// 调用领域服务禁用配置
return ecoMarketClientPublishConfigDomainService.disableConfig(uid, userContext);
}
/**
* 更新并启用配置
*
* @param request 更新配置参数
* @param userContext 用户上下文
* @return 启用后的配置模型
*/
@DSTransactional(rollbackFor = Exception.class)
@Override
public EcoMarketClientPublishConfigModel updateAndEnableConfig(UpdateAndEnableConfigReqDTO request, UserContext userContext) {
var uid = request.getUid();
var configParamJson = request.getConfigParamJson();
log.info("Application layer: update and enable config: uid={}, configParamJson={}", uid, configParamJson);
if (uid == null || uid.isEmpty()) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置UID");
}
// 然后启用配置
return ecoMarketClientPublishConfigDomainService.updateAndEnableConfig(request,userContext);
}
}

View File

@@ -0,0 +1,62 @@
package com.xspaceagi.eco.market.spec.app.service.impl;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientSecretModel;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientSecretDomainService;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.eco.market.spec.app.service.IEcoMarketClientSecretApplicationService;
import com.xspaceagi.system.spec.common.UserContext;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service
public class EcoMarketClientSecretApplicationService implements IEcoMarketClientSecretApplicationService {
@Resource
private IEcoMarketClientSecretDomainService ecoMarketClientSecretDomainService;
@Override
public EcoMarketClientSecretModel queryOneInfoById(Long id) {
return ecoMarketClientSecretDomainService.queryOneInfoById(id);
}
@Override
public List<EcoMarketClientSecretModel> queryListByIds(List<Long> ids) {
return ecoMarketClientSecretDomainService.queryListByIds(ids);
}
@Override
public void deleteById(Long id) {
ecoMarketClientSecretDomainService.deleteById(id);
}
@Override
public Long updateInfo(EcoMarketClientSecretModel model, UserContext userContext) {
return ecoMarketClientSecretDomainService.updateInfo(model, userContext);
}
@Override
public Long addInfo(EcoMarketClientSecretModel model, UserContext userContext) {
return ecoMarketClientSecretDomainService.addInfo(model, userContext);
}
@Override
@DSTransactional(rollbackFor = Exception.class)
public Long saveClientSecretDTO(ClientSecretDTO clientSecretDTO, UserContext userContext) {
log.info("Application layer: save client secret, tenantId: {}, clientId: {}", clientSecretDTO.getTenantId(), clientSecretDTO.getClientId());
return ecoMarketClientSecretDomainService.saveFromClientSecretDTO(clientSecretDTO, userContext);
}
@Override
public boolean existsClientSecret(Long tenantId) {
return ecoMarketClientSecretDomainService.existsClientSecret(tenantId);
}
}

View File

@@ -0,0 +1,137 @@
<?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-eco-market</artifactId>
<groupId>com.xspaceagi</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-platform-eco-market-client-web</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-eco-market-application</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 打包插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptors>
<!-- 打包配置必须在对应目录下创建repack.xml的打包配置文件 -->
<descriptor>src/main/resources/assemblies/repack.xml</descriptor>
</descriptors>
</configuration>
</plugin>
<!-- install插件定制在mvn install过程使用哪个jar包安装到本地 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
<executions>
<execution>
<id>install-file</id>
<goals>
<goal>install-file</goal>
</goals>
<phase>install</phase>
</execution>
</executions>
<configuration>
<!-- install配置指定将哪个目录下的jar包install为这个工程的jar -->
<file>${project.build.directory}/${project.build.finalName}-repack.jar</file>
<!--
install配置指定将install的jar打包使用的pom.xml文件
即其他依赖这个jar包的工程按照哪个pom.xml文件来解析依赖
-->
<pomFile>src/main/resources/install-pom.xml</pomFile>
</configuration>
</plugin>
<!-- deploy插件定制在mvn deploy过程使用哪个jar包发布到仓库 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<executions>
<execution>
<id>deploy-file</id>
<goals>
<goal>deploy-file</goal>
</goals>
<!-- 跳过默认的发布包 -->
<phase>none</phase>
</execution>
</executions>
<configuration>
<!-- deploy配置指定将哪个目录下的jar包发布为这个工程的jar -->
<file>${project.build.directory}/${project.build.finalName}-repack.jar</file>
<!-- 发布地址 -->
<url>http://local-maven.space.com/nexus/content/repositories/snapshots/</url>
<repositoryId>nexus-snapshots</repositoryId>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<packaging>jar</packaging>
<!--
deploy配置指定将deploy的jar打包使用的pom.xml文件
即其他依赖这个jar包的工程按照哪个pom.xml文件来解析依赖
-->
<pomFile>src/main/resources/install-pom.xml</pomFile>
</configuration>
</plugin>
<plugin>
<groupId>com.github.shalousun</groupId>
<artifactId>smart-doc-maven-plugin</artifactId>
<version>2.3.6</version>
<configuration>
<!--指定生成文档的使用的配置文件,配置文件放在自己的项目中-->
<configFile>./src/main/resources/smart-doc.json</configFile>
<!--指定项目名称-->
<projectName>${project.artifactId}</projectName>
<!--smart-doc实现自动分析依赖树加载第三方依赖的源码如果一些框架依赖库加载不到导致报错这时请使用excludes排除掉-->
<excludes>
<!--格式为groupId:artifactId;参考如下-->
<!--也可以支持正则式如com.alibaba:.* -->
<exclude>com.alibaba:fastjson</exclude>
</excludes>
<!--includes配置用于配置加载外部依赖源码,配置后插件会按照配置项加载外部源代码而不是自动加载所有,因此使用时需要注意-->
<!--smart-doc能自动分析依赖树加载所有依赖源码原则上会影响文档构建效率因此你可以使用includes来让插件加载你配置的组件-->
<includes></includes>
</configuration>
<executions>
<execution>
<goals>
<!--smart-doc提供了html、openapi、markdown等goal可按需配置-->
<goal>rpc-html</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,73 @@
package com.xspaceagi.eco.market.web.aspect;
import com.xspaceagi.eco.market.spec.annotation.RequireAdmin;
import com.xspaceagi.eco.market.spec.exception.AdminPermissionException;
import com.xspaceagi.system.spec.common.RequestContext;
import com.xspaceagi.system.application.dto.UserDto;
import com.xspaceagi.system.application.service.UserApplicationService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 管理员权限切面
* 用于拦截带有@RequireAdmin注解的方法验证当前用户是否为管理员
*
* @author soddy
*/
@Slf4j
@Aspect
@Component
public class AdminPermissionAspect {
@Autowired
private UserApplicationService userApplicationService;
/**
* 环绕通知,拦截带有@RequireAdmin注解的方法
*
* @param joinPoint 连接点
* @param requireAdmin 权限注解
* @return 方法执行结果
* @throws Throwable 异常
*/
@Around("@annotation(requireAdmin)")
public Object checkAdminPermission(ProceedingJoinPoint joinPoint, RequireAdmin requireAdmin) throws Throwable {
// 如果允许跳过权限检查,直接执行方法
if (requireAdmin.skipCheck()) {
log.debug("Skip admin permission check: {}", joinPoint.getSignature().getName());
return joinPoint.proceed();
}
try {
// 获取当前用户信息
UserDto currentUser = (UserDto) RequestContext.get().getUser();
if (currentUser == null) {
log.warn("User not logged in, access denied: {}", joinPoint.getSignature().getName());
throw new AdminPermissionException("用户未登录");
}
// 获取用户详细信息并检查是否为管理员
UserDto userDetail = userApplicationService.queryById(currentUser.getId());
// if (userDetail == null || !User.Role.Admin.equals(userDetail.getRole())) {
// log.warn("User [{}] is not admin, access denied: {}",
// currentUser.getId(), joinPoint.getSignature().getName());
// throw new AdminPermissionException(requireAdmin.value());
// }
log.debug("Admin check passed, user [{}] accessing: {}",
currentUser.getId(), joinPoint.getSignature().getName());
// 权限验证通过,执行目标方法
return joinPoint.proceed();
} catch (AdminPermissionException e) {
log.warn("Admin permission verification failed", e);
// 重新抛出权限异常
throw e;
}
}
}

View File

@@ -0,0 +1,291 @@
package com.xspaceagi.eco.market.web.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.eventbus.EventBus;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.specification.EcoMarkerSecretWrapper;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.eco.market.spec.app.dto.request.ClientConfigQueryRequest;
import com.xspaceagi.eco.market.spec.app.service.IEcoMarketClientConfigApplicationService;
import com.xspaceagi.eco.market.spec.constant.EcoMarketApiConstant;
import com.xspaceagi.eco.market.web.controller.base.BaseController;
import com.xspaceagi.eco.market.web.controller.dto.req.ClientConfigDetailReqDTO;
import com.xspaceagi.eco.market.web.controller.dto.req.ClientConfigSaveReqDTO;
import com.xspaceagi.eco.market.web.controller.dto.req.ClientConfigUpdateDraftReqDTO;
import com.xspaceagi.eco.market.web.controller.dto.req.ClientConfigUpdateReqDTO;
import com.xspaceagi.eco.market.web.controller.dto.resp.ClientConfigVo;
import com.xspaceagi.system.sdk.operate.ActionType;
import com.xspaceagi.system.sdk.operate.OperationLogReporter;
import com.xspaceagi.system.sdk.operate.SystemEnum;
import com.xspaceagi.system.spec.common.RequestContext;
import com.xspaceagi.system.spec.dto.ReqResult;
import com.xspaceagi.system.spec.event.PullMessageEvent;
import com.xspaceagi.system.spec.page.PageQueryVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Tag(name = "生态市场-客户端-配置")
@RestController
@RequestMapping(EcoMarketApiConstant.ClientConfig.BASE)
@Slf4j
public class EcoMarketClientConfigController extends BaseController {
@Resource
private IEcoMarketClientConfigApplicationService ecoMarketClientConfigApplicationService;
@Resource
private EcoMarkerSecretWrapper ecoMarkerSecretWrapper;
@Resource
private EventBus eventBus;
@OperationLogReporter(actionType = ActionType.QUERY, action = "客户端配置列表查询", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "客户端配置列表查询", description = "分页查询客户端配置列表,并比对服务器配置版本")
@RequestMapping(path = "/list", method = RequestMethod.POST)
public ReqResult<IPage<ClientConfigVo>> list(
@RequestBody PageQueryVo<ClientConfigQueryRequest> pageQueryVo) {
log.info("Query client config list: {}", pageQueryVo);
var userContext = getUser();
// 获取或注册客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(userContext.getTenantId());
if (clientSecret == null) {
return ReqResult.error("获取客户端密钥失败,请稍后重试");
}
// 执行分页查询,并比对服务器配置
IPage<EcoMarketClientConfigModel> modelPage = this.ecoMarketClientConfigApplicationService
.pageQueryWithServerCompare(pageQueryVo.getQueryFilter(), pageQueryVo.getCurrent(),
pageQueryVo.getPageSize(), clientSecret, userContext);
var superPage = modelPage.convert(model -> ClientConfigVo.convert2Dto(model));
// 注册成功后, 触发EventBus事件异步拉取消息
var clientId = clientSecret.getClientId();
var pullMessageEvent = PullMessageEvent.builder()
.userId(RequestContext.get().getUserId())
.tenantId(RequestContext.get().getTenantId())
.clientId(clientId)
.build();
eventBus.post(pullMessageEvent);
return ReqResult.success(superPage);
}
@OperationLogReporter(actionType = ActionType.QUERY, action = "客户端配置详情查询", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "客户端配置详情查询", description = "根据UID查询客户端配置详情")
@PostMapping("/detail")
public ReqResult<ClientConfigVo> getDetail(@RequestBody @Valid ClientConfigDetailReqDTO reqDTO) {
log.info("Query client config detail: uid={}", reqDTO.getUid());
// 获取当前用户上下文
var userContext = getUser();
var uid = reqDTO.getUid();
// 获取或注册客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(userContext.getTenantId());
if (clientSecret == null) {
return ReqResult.error("获取客户端密钥失败,请稍后重试");
}
// 调用应用服务获取配置详情
EcoMarketClientConfigModel configModel = ecoMarketClientConfigApplicationService.getConfigDetail(
uid, userContext);
if (configModel == null) {
return ReqResult.error("未找到对应配置信息");
}
// 转换为响应DTO
ClientConfigVo respDTO = ClientConfigVo.convert2Dto(configModel);
return ReqResult.success(respDTO);
}
@OperationLogReporter(actionType = ActionType.ADD, action = "新增草稿", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "新增草稿", description = "创建客户端配置草稿")
@PostMapping("/save/draft")
public ReqResult<ClientConfigVo> saveDraft(@RequestBody @Valid ClientConfigSaveReqDTO reqDTO) {
log.info("Save client config draft: {}", reqDTO);
// 获取当前用户上下文
var userContext = getUser();
// 获取或注册客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(userContext.getTenantId());
if (clientSecret == null) {
return ReqResult.error("获取客户端密钥失败,请稍后重试");
}
// 转换请求DTO为模型对象
EcoMarketClientConfigModel model = ClientConfigSaveReqDTO.convert2Dto(reqDTO, userContext);
// 调用应用服务创建草稿
EcoMarketClientConfigModel configModel = ecoMarketClientConfigApplicationService.saveDraft(
model, clientSecret.getClientId(), userContext);
// 转换为响应DTO
ClientConfigVo respDTO = ClientConfigVo.convert2Dto(configModel);
return ReqResult.success(respDTO);
}
@OperationLogReporter(actionType = ActionType.MODIFY, action = "更新草稿", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "更新草稿", description = "根据UID更新客户端配置草稿")
@PostMapping("/update/draft")
public ReqResult<ClientConfigVo> updateDraft(@RequestBody @Valid ClientConfigUpdateDraftReqDTO reqDTO) {
log.info("Update client config draft: uid={}, name={}", reqDTO.getUid(), reqDTO.getName());
// 获取当前用户上下文
var userContext = getUser();
// 获取或注册客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(userContext.getTenantId());
if (clientSecret == null) {
return ReqResult.error("获取客户端密钥失败,请稍后重试");
}
// 构建模型
EcoMarketClientConfigModel model = ClientConfigUpdateDraftReqDTO.convert2Dto(reqDTO, userContext);
// 设置客户端ID
model.setCreateClientId(clientSecret.getClientId());
// 调用应用服务更新草稿
EcoMarketClientConfigModel configModel = ecoMarketClientConfigApplicationService.updateDraft(model,
userContext);
// 转换为响应DTO
ClientConfigVo respDTO = ClientConfigVo.convert2Dto(configModel);
return ReqResult.success(respDTO);
}
@OperationLogReporter(actionType = ActionType.ADD, action = "保存并发布", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "保存并发布", description = "保存客户端配置并提交审核")
@PostMapping("/save/publish")
public ReqResult<ClientConfigVo> saveAndPublish(@RequestBody @Valid ClientConfigSaveReqDTO reqDTO) {
log.info("Save client config and publish: {}", reqDTO);
// 获取当前用户上下文
var userContext = getUser();
// 获取或注册客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(userContext.getTenantId());
if (clientSecret == null) {
return ReqResult.error("获取客户端密钥失败,请稍后重试");
}
// 构建模型
EcoMarketClientConfigModel model = ClientConfigSaveReqDTO.convert2Dto(reqDTO, userContext);
// 调用应用服务保存并发布
EcoMarketClientConfigModel configModel = ecoMarketClientConfigApplicationService.saveAndPublish(
model, clientSecret.getClientId(), clientSecret.getClientSecret(), userContext);
// 转换为响应DTO
ClientConfigVo respDTO = ClientConfigVo.convert2Dto(configModel);
return ReqResult.success(respDTO);
}
@OperationLogReporter(actionType = ActionType.MODIFY, action = "更新并发布", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "更新并发布", description = "更新客户端配置并提交审核")
@PostMapping("/update/publish")
public ReqResult<ClientConfigVo> updateAndPublish(@RequestBody @Valid ClientConfigUpdateReqDTO reqDTO) {
log.info("Update client config and publish: {}", reqDTO);
// 获取当前用户上下文
var userContext = getUser();
// 获取或注册客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(userContext.getTenantId());
if (clientSecret == null) {
return ReqResult.error("获取客户端密钥失败,请稍后重试");
}
// 构建模型
EcoMarketClientConfigModel model = ClientConfigUpdateReqDTO.convert2Dto(reqDTO, userContext);
// 调用应用服务保存并发布
EcoMarketClientConfigModel configModel = ecoMarketClientConfigApplicationService.saveAndPublish(
model, clientSecret.getClientId(), clientSecret.getClientSecret(), userContext);
// 转换为响应DTO
ClientConfigVo respDTO = ClientConfigVo.convert2Dto(configModel);
return ReqResult.success(respDTO);
}
@OperationLogReporter(actionType = ActionType.DELETE, action = "删除配置", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "删除配置", description = "删除客户端配置")
@PostMapping("/delete/{uid}")
public ReqResult<Boolean> delete(@PathVariable("uid") String uid) {
log.info("Delete client config: uid={}", uid);
var userContext = getUser();
// 获取或注册客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(userContext.getTenantId());
if (clientSecret == null) {
return ReqResult.error("获取客户端密钥失败,请稍后重试");
}
// 调用应用服务删除配置
boolean success = ecoMarketClientConfigApplicationService.deleteConfigByUid(uid, clientSecret, getUser());
return ReqResult.success(success);
}
@OperationLogReporter(actionType = ActionType.MODIFY, action = "下线配置", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "下线配置", description = "下线已发布的客户端配置")
@PostMapping("/offline/{uid}")
public ReqResult<ClientConfigVo> offline(@PathVariable("uid") String uid) {
log.info("Offline client config: uid={}", uid);
// 获取当前用户上下文
var userContext = getUser();
// 获取或注册客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(userContext.getTenantId());
if (clientSecret == null) {
return ReqResult.error("获取客户端密钥失败,请稍后重试");
}
// 调用应用服务下线配置
EcoMarketClientConfigModel configModel = ecoMarketClientConfigApplicationService.offlineConfigByUid(uid,
clientSecret,
userContext);
// 转换为响应DTO
ClientConfigVo respDTO = ClientConfigVo.convert2Dto(configModel);
return ReqResult.success(respDTO);
}
@OperationLogReporter(actionType = ActionType.MODIFY, action = "撤销发布", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "撤销发布", description = "撤销发布")
@PostMapping("/unpublish/{uid}")
public ReqResult<ClientConfigVo> unpublish(@PathVariable("uid") String uid) {
log.info("Revoke publish client config: uid={}", uid);
// 获取当前用户上下文
var userContext = getUser();
// 获取或注册客户端密钥
ClientSecretDTO clientSecret = ecoMarkerSecretWrapper.obtainClientSecretOrRegister(userContext.getTenantId());
if (clientSecret == null) {
return ReqResult.error("获取客户端密钥失败,请稍后重试");
}
// 调用应用服务下线配置
ecoMarketClientConfigApplicationService.unpublishConfigByUid(uid,
clientSecret,
userContext);
return ReqResult.success();
}
}

View File

@@ -0,0 +1,118 @@
package com.xspaceagi.eco.market.web.controller;
import com.xspaceagi.system.infra.service.QueryVoListDelegateService;
import com.xspaceagi.system.spec.exception.BizException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.spec.app.service.IEcoMarketClientPublishConfigApplicationService;
import com.xspaceagi.eco.market.spec.constant.EcoMarketApiConstant;
import com.xspaceagi.eco.market.web.controller.base.BaseController;
import com.xspaceagi.eco.market.domain.dto.req.UpdateAndEnableConfigReqDTO;
import com.xspaceagi.system.sdk.operate.ActionType;
import com.xspaceagi.system.sdk.operate.OperationLogReporter;
import com.xspaceagi.system.sdk.operate.SystemEnum;
import com.xspaceagi.system.spec.dto.ReqResult;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@Tag(name = "生态市场-客户端-发布配置")
@RestController
@RequestMapping(EcoMarketApiConstant.ClientPublishConfig.BASE)
@Slf4j
public class EcoMarketClientPublishConfigController extends BaseController {
@Resource
private QueryVoListDelegateService queryVoListDelegateService;
@Resource
private IEcoMarketClientPublishConfigApplicationService ecoMarketClientPublishConfigApplicationService;
/**
* 启用配置
*
* @param uid 配置唯一标识
* @return 启用结果
*/
@Operation(summary = "启用配置", description = "启用生态市场配置")
@PostMapping("/enable")
public ReqResult<EcoMarketClientPublishConfigModel> enableConfig(
@Parameter(description = "配置唯一标识") @RequestParam("uid") String uid) {
log.info("Enable config: uid={}", uid);
// 获取当前用户上下文
var userContext = getUser();
// 调用应用服务启用配置
EcoMarketClientPublishConfigModel result = ecoMarketClientPublishConfigApplicationService.enableConfig(uid,
userContext);
return ReqResult.success(result);
}
/**
* 更新保存并启用配置
* <p>
* 1. 入参: uid , configParamJson 请求参数配置
* </p>
*
* @param reqDTO 请求DTO包含配置唯一标识和配置参数JSON
* @return 启用结果
*/
@OperationLogReporter(actionType = ActionType.MODIFY, action = "更新保存并启用配置", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "更新保存并启用配置", description = "更新并启用生态市场配置")
@PostMapping("/updateAndEnable")
public ReqResult<EcoMarketClientPublishConfigModel> updateAndEnableConfig(
@RequestBody UpdateAndEnableConfigReqDTO reqDTO) {
log.info("Update save-and-enable config: reqDTO={}", reqDTO);
// 参数校验
if (reqDTO == null || reqDTO.getUid() == null || reqDTO.getUid().isEmpty()) {
throw BizException.of(BizExceptionCodeEnum.fieldRequiredButEmpty, "uid");
}
// 获取当前用户上下文
var userContext = getUser();
// 调用应用服务更新并启用配置
EcoMarketClientPublishConfigModel result = ecoMarketClientPublishConfigApplicationService
.updateAndEnableConfig(reqDTO, userContext);
return ReqResult.success(result);
}
/**
* 禁用配置
*
* @param uid 配置唯一标识
* @return 禁用结果
*/
@OperationLogReporter(actionType = ActionType.MODIFY, action = "禁用配置", objectName = "生态市场客户端配置", systemCode = SystemEnum.ECO_MARKET)
@Operation(summary = "禁用配置", description = "禁用生态市场配置")
@PostMapping("/disable")
public ReqResult<EcoMarketClientPublishConfigModel> disableConfig(
@Parameter(description = "配置唯一标识") @RequestParam("uid") String uid) {
log.info("Disable config: uid={}", uid);
// 获取当前用户上下文
var userContext = getUser();
// 调用应用服务禁用配置
EcoMarketClientPublishConfigModel result = ecoMarketClientPublishConfigApplicationService.disableConfig(uid,
userContext);
return ReqResult.success(result);
}
}

View File

@@ -0,0 +1,25 @@
package com.xspaceagi.eco.market.web.controller;
import com.xspaceagi.eco.market.spec.app.service.IEcoMarketClientSecretApplicationService;
import com.xspaceagi.eco.market.spec.constant.EcoMarketApiConstant;
import com.xspaceagi.eco.market.web.controller.base.BaseController;
import com.xspaceagi.system.infra.service.QueryVoListDelegateService;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "生态市场-客户端-密钥配置")
@RestController
@RequestMapping(EcoMarketApiConstant.ClientSecret.BASE)
@Slf4j
public class EcoMarketClientSecretConfigController extends BaseController {
@Resource
private QueryVoListDelegateService queryVoListDelegateService;
@Resource
private IEcoMarketClientSecretApplicationService ecoMarketClientSecretApplicationService;
}

View File

@@ -0,0 +1,35 @@
package com.xspaceagi.eco.market.web.controller.base;
import com.xspaceagi.system.spec.common.RequestContext;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.application.dto.UserDto;
import com.xspaceagi.system.infra.dao.entity.User;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public abstract class BaseController {
/**
* 获取当前登录用户信息
*
* @return
*/
public UserContext getUser() {
var userDto = (UserDto) RequestContext.get().getUser();
return UserContext.builder()
.userId(userDto.getId())
.userName(userDto.getUserName())
.nickName(userDto.getNickName())
.email(userDto.getEmail())
.phone(userDto.getPhone())
.status(userDto.getStatus() == User.Status.Enabled ? 1 : -1)
.tenantId(userDto.getTenantId())
.tenantName(null)
.orgId(null)
.orgName(null)
.roleType(null)
.build();
}
}

View File

@@ -0,0 +1,20 @@
package com.xspaceagi.eco.market.web.controller.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
/**
* 客户端配置详情请求DTO
*/
@Data
@Schema(description = "客户端配置详情请求DTO")
public class ClientConfigDetailReqDTO {
/**
* 配置UID
*/
@NotEmpty(message = "Configuration UID is required")
@Schema(description = "配置UID", required = true)
private String uid;
}

View File

@@ -0,0 +1,148 @@
package com.xspaceagi.eco.market.web.controller.dto.req;
import java.time.LocalDateTime;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.spec.enums.EcoMarketOwnedFlagEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketShareStatusEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketUseStatusEnum;
import com.xspaceagi.system.spec.common.UserContext;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
/**
* 客户端配置保存请求DTO
*/
@Getter
@Setter
@Schema(description = "客户端配置保存请求DTO")
public class ClientConfigSaveReqDTO {
/**
* 名称
*/
@NotBlank(message = "Name is required")
@Schema(description = "名称", requiredMode = RequiredMode.REQUIRED)
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
@NotNull(message = "Market type is required")
@Schema(description = "市场类型,1:插件;2:模板;3:MCP", requiredMode = RequiredMode.REQUIRED)
private Integer dataType;
/**
* 细分类型,比如: 插件,智能体,工作流
*/
@Schema(description = "细分类型,比如: 插件,智能体,工作流")
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
@Schema(description = "子类型")
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
@Schema(description = "具体目标的id,可以智能体,工作流,插件,还有mcp等")
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
@Schema(description = "分类编码,商业服务等,通过接口获取")
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
@Schema(description = "分类名称,商业服务等,通过接口获取")
private String categoryName;
/**
* 使用状态,1:启用;2:禁用;
*/
@Schema(description = "使用状态,1:启用;2:禁用;")
private Integer useStatus;
/**
* 作者信息
*/
@Schema(description = "作者信息")
private String author;
/**
* 发布文档
*/
@Schema(description = "发布文档")
private String publishDoc;
/**
* 请求参数配置json
*/
@Schema(description = "请求参数配置json")
private String configParamJson;
/**
* 图标图片地址
*/
@Schema(description = "图标图片地址")
private String icon;
public static EcoMarketClientConfigModel convert2Dto(ClientConfigSaveReqDTO reqDTO,UserContext userContext) {
var currentTime = LocalDateTime.now();
EcoMarketClientConfigModel ecoMarketClientConfigModel = EcoMarketClientConfigModel.builder()
.uid(null)
.name(reqDTO.getName())
.description(reqDTO.getDescription())
.dataType(reqDTO.getDataType())
.targetType(reqDTO.getTargetType())
.targetSubType(reqDTO.getTargetSubType())
.targetId(reqDTO.getTargetId())
.categoryCode(reqDTO.getCategoryCode())
.categoryName(reqDTO.getCategoryName())
.ownedFlag(EcoMarketOwnedFlagEnum.YES.getCode())
.shareStatus(EcoMarketShareStatusEnum.DRAFT.getCode())
.useStatus(EcoMarketUseStatusEnum.ENABLED.getCode())
.publishTime(currentTime)
.offlineTime(null)
.versionNumber(1L)
.author(reqDTO.getAuthor())
.publishDoc(reqDTO.getPublishDoc())
.configParamJson(reqDTO.getConfigParamJson())
.configJson(null)
.icon(reqDTO.getIcon())
.tenantId(userContext.getTenantId())
.createClientId(null)
.created(currentTime)
.creatorId(userContext.getUserId())
.creatorName(userContext.getUserName())
.modified(currentTime)
.modifiedId(null)
.modifiedName(null)
.isNewVersion(null)
.serverVersionNumber(null)
.build();
return ecoMarketClientConfigModel;
}
}

View File

@@ -0,0 +1,41 @@
package com.xspaceagi.eco.market.web.controller.dto.req;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.system.spec.common.UserContext;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
/**
* 客户端配置更新草稿请求DTO
*/
@Getter
@Setter
@Schema(description = "客户端配置更新草稿请求DTO")
public class ClientConfigUpdateDraftReqDTO extends ClientConfigSaveReqDTO {
/**
* 配置唯一标识
*/
@NotBlank(message = "Configuration UID is required")
@Schema(description = "配置唯一标识", requiredMode = RequiredMode.REQUIRED)
private String uid;
/**
* 将DTO转换为模型对象
*
* @param reqDTO 请求DTO
* @param userContext 用户上下文
* @return 模型对象
*/
public static EcoMarketClientConfigModel convert2Dto(ClientConfigUpdateDraftReqDTO reqDTO, UserContext userContext) {
// 使用父类的转换方法
EcoMarketClientConfigModel model = ClientConfigSaveReqDTO.convert2Dto(reqDTO, userContext);
// 设置uid
model.setUid(reqDTO.getUid());
return model;
}
}

View File

@@ -0,0 +1,152 @@
package com.xspaceagi.eco.market.web.controller.dto.req;
import java.time.LocalDateTime;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.spec.enums.EcoMarketOwnedFlagEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketShareStatusEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketUseStatusEnum;
import com.xspaceagi.system.spec.common.UserContext;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
/**
* 客户端配置更新请求DTO
*/
@Getter
@Setter
@Schema(description = "客户端配置更新请求DTO")
public class ClientConfigUpdateReqDTO {
/**
* 配置UID
*/
@NotBlank(message = "Configuration UID is required")
@Schema(description = "配置UID", required = true)
private String uid;
/**
* 名称
*/
@NotBlank(message = "Name is required")
@Schema(description = "名称", requiredMode = RequiredMode.REQUIRED)
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
@NotNull(message = "Market type is required")
@Schema(description = "市场类型,1:插件;2:模板;3:MCP", requiredMode = RequiredMode.REQUIRED)
private Integer dataType;
/**
* 细分类型,比如: 插件,智能体,工作流
*/
@Schema(description = "细分类型,比如: 插件,智能体,工作流")
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
@Schema(description = "子类型")
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
@Schema(description = "具体目标的id,可以智能体,工作流,插件,还有mcp等")
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
@Schema(description = "分类编码,商业服务等,通过接口获取")
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
@Schema(description = "分类名称,商业服务等,通过接口获取")
private String categoryName;
/**
* 使用状态,1:启用;2:禁用;
*/
@Schema(description = "使用状态,1:启用;2:禁用;")
private Integer useStatus;
/**
* 作者信息
*/
@Schema(description = "作者信息")
private String author;
/**
* 发布文档
*/
@Schema(description = "发布文档")
private String publishDoc;
/**
* 请求参数配置json
*/
@Schema(description = "请求参数配置json")
private String configParamJson;
/**
* 图标图片地址
*/
@Schema(description = "图标图片地址")
private String icon;
public static EcoMarketClientConfigModel convert2Dto(ClientConfigUpdateReqDTO reqDTO, UserContext userContext) {
var currentTime = LocalDateTime.now();
EcoMarketClientConfigModel ecoMarketClientConfigModel = EcoMarketClientConfigModel.builder()
.uid(reqDTO.getUid())
.name(reqDTO.getName())
.description(reqDTO.getDescription())
.dataType(reqDTO.getDataType())
.targetType(reqDTO.getTargetType())
.targetSubType(reqDTO.getTargetSubType())
.targetId(reqDTO.getTargetId())
.categoryCode(reqDTO.getCategoryCode())
.categoryName(reqDTO.getCategoryName())
.ownedFlag(EcoMarketOwnedFlagEnum.YES.getCode())
.shareStatus(EcoMarketShareStatusEnum.DRAFT.getCode())
.useStatus(EcoMarketUseStatusEnum.ENABLED.getCode())
.publishTime(currentTime)
.offlineTime(null)
.versionNumber(1L)
.author(reqDTO.getAuthor())
.publishDoc(reqDTO.getPublishDoc())
.configParamJson(reqDTO.getConfigParamJson())
.configJson(null)
.icon(reqDTO.getIcon())
.tenantId(userContext.getTenantId())
.createClientId(null)
.created(currentTime)
.creatorId(userContext.getUserId())
.creatorName(userContext.getUserName())
.modified(currentTime)
.modifiedId(null)
.modifiedName(null)
.isNewVersion(null)
.serverVersionNumber(null)
.build();
return ecoMarketClientConfigModel;
}
}

View File

@@ -0,0 +1,22 @@
package com.xspaceagi.eco.market.web.controller.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(description = "发布配置详情请求DTO")
public class ServerConfigPublishDetailReqDTO {
@Schema(description = "配置唯一标识")
@NotBlank(message = "uid is required")
private String uid;
@Schema(description = "客户端ID")
@NotBlank(message = "clientId is required")
private String clientId;
@Schema(description = "客户端密钥")
@NotBlank(message = "clientSecret is required")
private String clientSecret;
}

View File

@@ -0,0 +1,302 @@
package com.xspaceagi.eco.market.web.controller.dto.resp;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import com.xspaceagi.custompage.sdk.dto.SourceTypeEnum;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.system.application.util.DefaultIconUrlUtil;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 客户端配置响应VO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "客户端配置响应VO")
public class ClientConfigVo {
/**
* 主键id
*/
@Schema(description = "主键id")
private Long id;
/**
* 唯一ID,分布式唯一UUID
*/
@Schema(description = "唯一ID,分布式唯一UUID")
private String uid;
/**
* 名称
*/
@Schema(description = "名称")
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
@Schema(description = "市场类型,默认插件,1:插件;2:模板;3:MCP")
private Integer dataType;
/**
* 细分类型,比如: 插件,智能体,工作流
*/
@Schema(description = "细分类型,比如: 插件,智能体,工作流")
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
@Schema(description = "子类型")
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
@Schema(description = "具体目标的id,可以智能体,工作流,插件,还有mcp等")
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
@Schema(description = "分类编码,商业服务等,通过接口获取")
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
@Schema(description = "分类名称,商业服务等,通过接口获取")
private String categoryName;
/**
* 是否我的分享,0:否(生态市场获取的);1:是(我的分享)
*/
@Schema(description = "是否我的分享,0:否(生态市场获取的);1:是(我的分享)")
private Integer ownedFlag;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
@Schema(description = "分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回")
private Integer shareStatus;
/**
* 使用状态,1:启用;2:禁用;
*/
@Schema(description = "使用状态,1:启用;2:禁用;")
private Integer useStatus;
/**
* 发布时间
*/
@Schema(description = "发布时间")
private LocalDateTime publishTime;
/**
* 下线时间
*/
@Schema(description = "下线时间")
private LocalDateTime offlineTime;
/**
* 版本号,自增,发布一次增加1,初始值为1
*/
@Schema(description = "版本号,自增,发布一次增加1,初始值为1")
private Long versionNumber;
/**
* 作者信息
*/
@Schema(description = "作者信息")
private String author;
/**
* 发布文档
*/
@Schema(description = "发布文档")
private String publishDoc;
/**
* 请求参数配置json,生态市场拉取的最新的配置
*/
@Schema(description = "请求参数配置json")
private String configParamJson;
/**
* 当前本地的原始配置
*/
@Schema(description = "当前本地的原始配置")
private String localConfigParamJson;
/**
* 服务器配置参数json,存储服务器配置的参数信息
*/
@Schema(description = "服务器配置参数json,存储服务器配置的参数信息")
private String serverConfigParamJson;
/**
* 配置json,存储插件的配置信息如果有其他额外的信息保存放这里
*/
@Schema(description = "配置json,存储插件的配置信息如果有其他额外的信息保存放这里")
private String configJson;
/**
* 当前本地的原始配置json
*/
@Schema(description = "当前本地的原始配置json")
private String localConfigJson;
/**
* 服务器配置json
*/
@Schema(description = "服务器配置json")
private String serverConfigJson;
/**
* 图标图片地址
*/
@Schema(description = "图标图片地址")
private String icon;
/**
* 审批信息
*/
@Schema(description = "审批信息")
private String approveMessage;
/**
* 租户ID
*/
@Schema(description = "租户ID")
private Long tenantId;
/**
* 所属空间ID
*/
@Schema(description = "所属空间ID")
private Long spaceId;
/**
* 创建者的客户端ID
*/
@Schema(description = "创建者的客户端ID")
private String createClientId;
/**
* 创建时间
*/
@Schema(description = "创建时间")
private LocalDateTime created;
/**
* 创建人id
*/
@Schema(description = "创建人id")
private Long creatorId;
/**
* 创建人
*/
@Schema(description = "创建人")
private String creatorName;
/**
* 更新时间
*/
@Schema(description = "更新时间")
private LocalDateTime modified;
/**
* 最后修改人id
*/
@Schema(description = "最后修改人id")
private Long modifiedId;
/**
* 最后修改人
*/
@Schema(description = "最后修改人")
private String modifiedName;
/**
* 是否有新版本,true:是;false:否
*/
@Schema(description = "是否有新版本,true:是;false:否")
private Boolean isNewVersion;
/**
* 服务器端最新版本号
*/
@Schema(description = "服务器端最新版本号")
private Long serverVersionNumber;
@Schema(description = "封面图片")
private String coverImg;
@Schema(description = "图片图片来源")
private SourceTypeEnum coverImgSourceType;
/**
* 将模型转换为DTO
*/
public static ClientConfigVo convert2Dto(EcoMarketClientConfigModel model) {
if (model == null) {
return null;
}
ClientConfigVo clientConfigVo = ClientConfigVo.builder()
.id(model.getId())
.uid(model.getUid())
.name(model.getName())
.description(model.getDescription())
.dataType(model.getDataType())
.targetType(model.getTargetType())
.targetSubType(model.getTargetSubType())
.targetId(model.getTargetId())
.categoryCode(model.getCategoryCode())
.categoryName(model.getCategoryName())
.ownedFlag(model.getOwnedFlag())
.shareStatus(model.getShareStatus())
.useStatus(model.getUseStatus())
.publishTime(model.getPublishTime())
.offlineTime(model.getOfflineTime())
.versionNumber(model.getVersionNumber())
.author(model.getAuthor())
.publishDoc(model.getPublishDoc())
.configParamJson(model.getConfigParamJson())
.localConfigParamJson(model.getLocalConfigParamJson())
.serverConfigParamJson(model.getServerConfigParamJson())
.configJson(model.getConfigJson())
.localConfigJson(model.getLocalConfigJson())
.serverConfigJson(model.getServerConfigJson())
.icon(model.getIcon())
.approveMessage(model.getApproveMessage())
.tenantId(model.getTenantId())
.createClientId(model.getCreateClientId())
.created(model.getCreated())
.creatorId(model.getCreatorId())
.creatorName(model.getCreatorName())
.modified(model.getModified())
.modifiedId(model.getModifiedId())
.modifiedName(model.getModifiedName())
.isNewVersion(model.getIsNewVersion())
.serverVersionNumber(model.getServerVersionNumber())
.coverImg(model.getCoverImg())
.coverImgSourceType(model.getCoverImgSourceType())
.build();
clientConfigVo.setIcon(DefaultIconUrlUtil.setDefaultIconUrl(clientConfigVo.getIcon(), clientConfigVo.getName(), model.getTargetType()));
return clientConfigVo;
}
}

View File

@@ -0,0 +1,35 @@
package com.xspaceagi.eco.market.web.exception;
import com.xspaceagi.eco.market.spec.exception.AdminPermissionException;
import com.xspaceagi.system.spec.dto.ReqResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 全局异常处理器
* 用于处理权限相关异常
*
* @author soddy
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理管理员权限异常
*
* @param e 权限异常
* @return 错误响应
*/
@ExceptionHandler(AdminPermissionException.class)
@ResponseStatus(HttpStatus.FORBIDDEN)
public ReqResult<Void> handleAdminPermissionException(AdminPermissionException e) {
log.warn("Admin permission verification failed", e);
ReqResult<Void> responseData = ReqResult.error(e.getMessage());
return responseData;
}
}

View File

@@ -0,0 +1,32 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>repack</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<!--
重新打包需要包含的jar包,这个过程会解压所有的jar包并按照jar的规则重新组合成一个jar包
这里需要包含当前这个工程 ,格式是{groupId}:{artifactId}
-->
<includes>
<!-- 包含项目自己 -->
<include>com.xspaceagi:app-platform-eco-market-web</include>
<include>com.xspaceagi:app-platform-eco-market-application</include>
<include>com.xspaceagi:app-platform-eco-market-domain</include>
<include>com.xspaceagi:app-platform-eco-market-infra</include>
<include>com.xspaceagi:app-platform-eco-market-spec</include>
</includes>
<!-- 打包结果目录:/ 表示target/ -->
<outputDirectory>/</outputDirectory>
<!-- 是否解压依赖 -->
<unpack>true</unpack>
<!-- 打包的scope -->
<!-- <scope>system</scope>-->
</dependencySet>
</dependencySets>
</assembly>

View File

@@ -0,0 +1,21 @@
<?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-eco-market-web</artifactId>
<groupId>com.xspaceagi</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-platform-eco-market-web</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,48 @@
<?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-eco-market</artifactId>
<groupId>com.xspaceagi</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>app-platform-eco-market-domain</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<dependencies>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-eco-market-spec</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-agent-core-adapter</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-agent-core-sdk</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-eco-market-sdk</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-mcp-sdk</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-custom-page-application</artifactId>
</dependency>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-pay-spec</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,74 @@
package com.xspaceagi.eco.market.domain.adaptor;
import com.xspaceagi.agent.core.sdk.dto.AgentInfoDto;
import com.xspaceagi.agent.core.sdk.dto.PluginEnableOrUpdateDto;
import com.xspaceagi.agent.core.sdk.dto.TemplateEnableOrUpdateDto;
import com.xspaceagi.agent.core.sdk.enums.TargetTypeEnum;
import com.xspaceagi.mcp.sdk.dto.McpDto;
import java.util.List;
public interface IEcoMarketAdaptor {
List<AgentInfoDto> queryAgentInfoList(List<Long> agentIds);
/**
* 查询插件配置信息
*
* @param pluginId
* @param paramJson
* @return
*/
String queryPluginConfig(Long pluginId, String paramJson);
/**
* 插件启动或更新
*
* @return 返回系统生成的插件ID
*/
Long pluginEnableOrUpdate(PluginEnableOrUpdateDto pluginEnableOrUpdateDto);
/**
* 禁用插件
*
* @return
*/
Void disablePlugin(Long pluginId);
/**
* 查询模板配置信息(智能体、工作流)
*
* @return
*/
String queryTemplateConfig(TargetTypeEnum targetType, Long targetId);
/**
* 模板启动或更新
*
* @return 系统生成的工作流或智能体ID
*/
Long templateEnableOrUpdate(TemplateEnableOrUpdateDto templateEnableOrUpdateDto);
/**
* 禁用模板
*
* @return
*/
Void disableTemplate(TargetTypeEnum targetType, Long targetId);
/**
* 部署MCP
* @param mcpDto
* @return
*/
Long deployOfficialMcp(McpDto mcpDto);
/**
* 停止MCP
* @param targetId
* @return
*/
Void stopOfficialMcp(Long targetId);
}

View File

@@ -0,0 +1,239 @@
package com.xspaceagi.eco.market.domain.adaptor.impl;
import java.util.Collections;
import java.util.List;
import com.xspaceagi.mcp.sdk.IMcpApiService;
import com.xspaceagi.mcp.sdk.dto.McpDto;
import org.springframework.stereotype.Service;
import com.xspaceagi.agent.core.sdk.IAgentRpcService;
import com.xspaceagi.agent.core.sdk.dto.AgentInfoDto;
import com.xspaceagi.agent.core.sdk.dto.PluginEnableOrUpdateDto;
import com.xspaceagi.agent.core.sdk.dto.TemplateEnableOrUpdateDto;
import com.xspaceagi.agent.core.sdk.enums.TargetTypeEnum;
import com.xspaceagi.eco.market.domain.adaptor.IEcoMarketAdaptor;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class EcoMarketAdaptor implements IEcoMarketAdaptor {
@Resource
private IAgentRpcService agentRpcService;
/**
* MCP API服务
*/
@Resource
private IMcpApiService mcpApiService;
@Override
public List<AgentInfoDto> queryAgentInfoList(List<Long> agentIds) {
try {
log.info("Agent RPC list agents: agentIds={}", agentIds);
if (agentIds == null || agentIds.isEmpty()) {
return Collections.emptyList();
}
var result = agentRpcService.queryAgentInfoList(agentIds);
if (result == null || !result.isSuccess()) {
log.error("List agents failed: agentIds={}, errorCode={}, errorMsg={}",
agentIds, result != null ? result.getCode() : "NULL",
result != null ? result.getMessage() : "NULL");
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "查询Agent信息列表失败");
}
return result.getData() != null ? result.getData() : Collections.emptyList();
} catch (EcoMarketException e) {
// 已经是我们自定义的异常,直接抛出
throw e;
} catch (Exception e) {
log.error("List agents error: agentIds={}", agentIds, e);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound,
"查询Agent信息列表异常: " + e.getMessage());
}
}
@Override
public String queryPluginConfig(Long pluginId, String paramJson) {
try {
log.info("Agent RPC get plugin config: pluginId={}, paramJson={}", pluginId, paramJson);
if (pluginId == null) {
throw new IllegalArgumentException("Plugin ID cannot be empty");
}
var result = agentRpcService.queryPluginConfig(pluginId, paramJson);
if (result == null || !result.isSuccess()) {
log.error("Get plugin config failed: pluginId={}, errorCode={}, errorMsg={}",
pluginId, result != null ? result.getCode() : "NULL",
result != null ? result.getMessage() : "NULL");
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "查询插件配置失败");
}
return result.getData();
} catch (EcoMarketException e) {
throw e;
} catch (Exception e) {
log.error("Get plugin config error: pluginId={}", pluginId, e);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "查询插件配置异常: " + e.getMessage());
}
}
@Override
public Long pluginEnableOrUpdate(PluginEnableOrUpdateDto pluginEnableOrUpdateDto) {
try {
log.info("Agent RPC enable/update plugin: pluginEnableOrUpdateDto={}", pluginEnableOrUpdateDto);
if (pluginEnableOrUpdateDto == null) {
throw new IllegalArgumentException("Plugin enable or update DTO cannot be empty");
}
var result = agentRpcService.pluginEnableOrUpdate(pluginEnableOrUpdateDto);
if (result == null || !result.isSuccess()) {
log.error("Enable/update plugin failed: errorCode={}, errorMsg={}",
result != null ? result.getCode() : "NULL", result != null ? result.getMessage() : "NULL");
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "启用或更新插件失败");
}
return result.getData();
} catch (EcoMarketException e) {
throw e;
} catch (Exception e) {
log.error("Enable/update plugin error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "启用或更新插件异常: " + e.getMessage());
}
}
@Override
public Void disablePlugin(Long pluginId) {
try {
log.info("Agent RPC disable plugin: pluginId={}", pluginId);
if (pluginId == null) {
throw new IllegalArgumentException("Plugin ID cannot be empty");
}
var result = agentRpcService.disablePlugin(pluginId);
if (result == null || !result.isSuccess()) {
log.error("Disable plugin failed: pluginId={}, errorCode={}, errorMsg={}",
pluginId, result != null ? result.getCode() : "NULL",
result != null ? result.getMessage() : "NULL");
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "禁用插件失败");
}
return null;
} catch (EcoMarketException e) {
throw e;
} catch (Exception e) {
log.error("Disable plugin error: pluginId={}", pluginId, e);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "禁用插件异常: " + e.getMessage());
}
}
@Override
public String queryTemplateConfig(TargetTypeEnum targetType, Long targetId) {
try {
log.info("Agent RPC get template config: targetType={}, targetId={}", targetType, targetId);
if (targetType == null || targetId == null) {
throw new IllegalArgumentException("Target type or target ID cannot be empty");
}
var result = agentRpcService.queryTemplateConfig(targetType, targetId);
if (result == null || !result.isSuccess()) {
log.error("Get template config failed: targetType={}, targetId={}, errorCode={}, errorMsg={}",
targetType, targetId, result != null ? result.getCode() : "NULL",
result != null ? result.getMessage() : "NULL");
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "查询模板配置失败");
}
return result.getData();
} catch (EcoMarketException e) {
throw e;
} catch (Exception e) {
log.error("Get template config error: targetType={}, targetId={}", targetType, targetId, e);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "查询模板配置异常: " + e.getMessage());
}
}
@Override
public Long templateEnableOrUpdate(TemplateEnableOrUpdateDto templateEnableOrUpdateDto) {
try {
log.info("Agent RPC enable/update template: templateEnableOrUpdateDto={}", templateEnableOrUpdateDto);
if (templateEnableOrUpdateDto == null) {
throw new IllegalArgumentException("Template enable or update DTO cannot be empty");
}
var result = agentRpcService.templateEnableOrUpdate(templateEnableOrUpdateDto);
if (result == null || !result.isSuccess()) {
log.error("Enable/update template failed: errorCode={}, errorMsg={}",
result != null ? result.getCode() : "NULL", result != null ? result.getMessage() : "NULL");
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "启用或更新模板失败");
}
return result.getData();
} catch (EcoMarketException e) {
throw e;
} catch (Exception e) {
log.error("Enable/update template error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "启用或更新模板异常: " + e.getMessage());
}
}
@Override
public Void disableTemplate(TargetTypeEnum targetType, Long targetId) {
try {
log.info("Agent RPC disable template: targetType={}, targetId={}", targetType, targetId);
if (targetType == null || targetId == null) {
throw new IllegalArgumentException("Target type or target ID cannot be empty");
}
var result = agentRpcService.disableTemplate(targetType, targetId);
if (result == null || !result.isSuccess()) {
log.error("Disable template failed: targetType={}, targetId={}, errorCode={}, errorMsg={}",
targetType, targetId, result != null ? result.getCode() : "NULL",
result != null ? result.getMessage() : "NULL");
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "禁用模板失败");
}
return null;
} catch (EcoMarketException e) {
throw e;
} catch (Exception e) {
log.error("Disable template error: targetType={}, targetId={}", targetType, targetId, e);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "禁用模板异常: " + e.getMessage());
}
}
@Override
public Long deployOfficialMcp(McpDto mcpDto) {
log.info("MCP API deploy MCP: mcpDto={}", mcpDto);
if (mcpDto == null) {
log.error("Deploy MCP failed: MCP config required");
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "MCP配置");
}
var result = mcpApiService.deployOfficialMcp(mcpDto);
if (result == null) {
log.error("Deploy MCP failed: mcpDto={}", mcpDto);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketDeployMcpFailed);
}
return result;
}
@Override
public Void stopOfficialMcp(Long targetId) {
log.info("MCP API stop MCP: targetId={}", targetId);
if (targetId == null) {
log.error("Stop MCP failed: MCP ID required");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketStopMcpFailed);
}
mcpApiService.stopOfficialMcp(targetId);
return null;
}
}

View File

@@ -0,0 +1,123 @@
package com.xspaceagi.eco.market.domain.assembler;
import java.time.LocalDateTime;
import org.springframework.stereotype.Component;
import com.xspaceagi.eco.market.domain.dto.resp.ServerConfigDetailRespDTO;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.spec.enums.EcoMarketOwnedFlagEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketShareStatusEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketUseStatusEnum;
import lombok.extern.slf4j.Slf4j;
/**
* 生态市场配置对象转换器
* 用于不同配置对象之间的转换
*/
@Slf4j
@Component
public class EcoMarketConfigTranslator {
/**
* 将服务器配置详情转换为客户端配置模型
*
* @param serverConfig 服务器配置详情
* @param tenantId 租户ID
* @return 客户端配置模型
*/
public EcoMarketClientConfigModel translateServerConfigToClientConfig(ServerConfigDetailRespDTO serverConfig,
Long tenantId) {
if (serverConfig == null) {
return null;
}
EcoMarketClientConfigModel configModel = new EcoMarketClientConfigModel();
configModel.setUid(serverConfig.getUid());
configModel.setName(serverConfig.getName());
configModel.setDescription(serverConfig.getDescription());
// 设置配置内容
configModel.setConfigJson(serverConfig.getConfigJson());
// 设置其他字段
if (serverConfig.getVersionNumber() != null) {
configModel.setVersionNumber(serverConfig.getVersionNumber());
} else {
configModel.setVersionNumber(1L);
}
// 设置其他必要字段
configModel.setShareStatus(EcoMarketShareStatusEnum.PUBLISHED.getCode());
configModel.setUseStatus(EcoMarketUseStatusEnum.DISABLED.getCode());
configModel.setOwnedFlag(EcoMarketOwnedFlagEnum.NO.getCode()); // 不是自己分享的
configModel.setTenantId(null);
// 复制其他可用字段
configModel.setDataType(serverConfig.getDataType());
configModel.setTargetType(serverConfig.getTargetType());
configModel.setTargetSubType(serverConfig.getTargetSubType());
configModel.setTargetId(serverConfig.getTargetId());
configModel.setCategoryCode(serverConfig.getCategoryCode());
configModel.setCategoryName(serverConfig.getCategoryName());
configModel.setAuthor(serverConfig.getAuthor());
configModel.setPublishDoc(serverConfig.getPublishDoc());
configModel.setConfigParamJson(serverConfig.getConfigParamJson());
configModel.setIcon(serverConfig.getIcon());
configModel.setPageZipUrl(serverConfig.getPageZipUrl());
// 设置发布时间
configModel.setPublishTime(LocalDateTime.now());
return configModel;
}
/**
* 将客户端配置转换为发布配置
*
* @param clientConfig 客户端配置模型
* @return 发布配置模型
*/
public EcoMarketClientPublishConfigModel translateClientConfigToPublishConfig(
EcoMarketClientConfigModel clientConfig) {
if (clientConfig == null) {
return null;
}
EcoMarketClientPublishConfigModel publishConfig = new EcoMarketClientPublishConfigModel();
publishConfig.setUid(clientConfig.getUid());
publishConfig.setName(clientConfig.getName());
publishConfig.setDescription(clientConfig.getDescription());
publishConfig.setDataType(clientConfig.getDataType());
publishConfig.setTargetType(clientConfig.getTargetType());
publishConfig.setTargetSubType(clientConfig.getTargetSubType());
publishConfig.setTargetId(clientConfig.getTargetId());
publishConfig.setCategoryCode(clientConfig.getCategoryCode());
publishConfig.setCategoryName(clientConfig.getCategoryName());
publishConfig.setOwnedFlag(clientConfig.getOwnedFlag());
publishConfig.setShareStatus(clientConfig.getShareStatus());
publishConfig.setUseStatus(clientConfig.getUseStatus());
publishConfig.setPublishTime(clientConfig.getPublishTime());
publishConfig.setVersionNumber(clientConfig.getVersionNumber());
publishConfig.setAuthor(clientConfig.getAuthor());
publishConfig.setPublishDoc(clientConfig.getPublishDoc());
publishConfig.setConfigParamJson(clientConfig.getConfigParamJson());
publishConfig.setConfigJson(clientConfig.getConfigJson());
publishConfig.setIcon(clientConfig.getIcon());
publishConfig.setTenantId(clientConfig.getTenantId());
publishConfig.setCreateClientId(clientConfig.getCreateClientId());
publishConfig.setPageZipUrl(clientConfig.getPageZipUrl());
return publishConfig;
}
}

View File

@@ -0,0 +1,903 @@
package com.xspaceagi.eco.market.domain.client;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xspaceagi.agent.core.adapter.application.ModelApplicationService;
import com.xspaceagi.agent.core.adapter.dto.config.ModelConfigDto;
import com.xspaceagi.agent.core.adapter.repository.entity.ModelConfig;
import com.xspaceagi.agent.core.spec.enums.ModelApiProtocolEnum;
import com.xspaceagi.agent.core.spec.enums.ModelFunctionCallEnum;
import com.xspaceagi.agent.core.spec.enums.ModelTypeEnum;
import com.xspaceagi.eco.market.domain.config.EcoMarketConfig;
import com.xspaceagi.eco.market.domain.dto.req.ClientRegisterReqDTO;
import com.xspaceagi.eco.market.domain.dto.req.ClientValidateReqDTO;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigBatchDetailReqDTO;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigDetailReqDTO;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigOfflineReqDTO;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigQueryRequest;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigSaveReqDTO;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigStatusReqDTO;
import com.xspaceagi.eco.market.domain.dto.req.ServerConfigUnpublishReqDTO;
import com.xspaceagi.eco.market.domain.dto.resp.ServerConfigDetailRespDTO;
import com.xspaceagi.eco.market.domain.dto.resp.ServerConfigListRespDTO;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.eco.market.spec.constant.EcoMarketApiConstant;
import com.xspaceagi.system.spec.dto.ReqResult;
import com.xspaceagi.system.spec.enums.YesOrNoEnum;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import com.xspaceagi.system.spec.page.PageQueryVo;
import com.xspaceagi.system.spec.page.SuperPage;
import com.xspaceagi.system.spec.tenant.thread.TenantFunctions;
import com.xspaceagi.system.spec.utils.RedisUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* 生态市场服务器API调用服务
* 封装客户端对服务器端API的调用
*/
@Slf4j
@Service
@DependsOn({"ecoMarketConfig", "ecoMarketProperties"})
public class EcoMarketServerApiService {
private final OkHttpClient httpClient;
private String serverBaseUrl;
private static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json; charset=utf-8");
@Resource
private ModelApplicationService modelApplicationService;
@Resource
private RedisUtil redisUtil;
@Resource
private EcoMarketConfig ecoMarketConfig;
public EcoMarketServerApiService() {
this.httpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
log.info("Init eco-market server API client (Fastjson2 JSON)");
}
/**
* 初始化方法在Spring容器完全初始化Bean后调用
*/
@PostConstruct
public void init() {
try {
this.serverBaseUrl = ecoMarketConfig.getServerBaseUrl();
log.info("Init eco-market server API client, URL: {}", this.serverBaseUrl);
} catch (Exception e) {
log.warn("Eco-market config init error, will retry on first use: {}", e.getMessage());
}
}
/**
* 构建API URL
*
* @param apiPath API路径
* @return 完整的API URL
*/
private String buildApiUrl(String apiPath) {
// 如果初始化时未能获取URL这里再次尝试
if (serverBaseUrl == null) {
try {
serverBaseUrl = ecoMarketConfig.getServerBaseUrl();
log.info("Lazy init eco-market server API URL: {}", serverBaseUrl);
} catch (Exception e) {
log.error("Get server base URL failed", e);
throw new RuntimeException("无法获取生态市场服务器基础URL请检查eco-market.server.base-url配置", e);
}
}
String baseUrl = serverBaseUrl;
if (baseUrl.endsWith("/")) {
baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
}
if (apiPath.startsWith("/")) {
apiPath = apiPath.substring(1);
}
return baseUrl + "/" + apiPath;
}
/**
* 注册客户端
*
* @param name 客户端名称
* @param description 客户端描述
* @param tenantId 租户ID
* @return 注册结果包含客户端ID和密钥
*/
public ClientSecretDTO registerClient(String name, String description, Long tenantId, String clientId) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/secret/register");
// 构建请求DTO
ClientRegisterReqDTO reqDTO = new ClientRegisterReqDTO();
reqDTO.setName(name);
reqDTO.setDescription(description);
reqDTO.setTenantId(tenantId);
reqDTO.setClientId(clientId);
// 构建请求体
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Client register request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound,
"请求失败,状态码: " + response.code());
}
String responseBody = null;
if (response.body() != null) {
responseBody = response.body().string();
}
ReqResult<ClientSecretDTO> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<ClientSecretDTO>>() {
});
if (result != null && result.isSuccess()) {
// 保存默认会话模型配置
modelApplicationService
.addOrUpdate(buildModelConfig(tenantId, ModelTypeEnum.Chat, 1L));
// 保存默认嵌入模型配置
modelApplicationService
.addOrUpdate(buildModelConfig(tenantId, ModelTypeEnum.Embeddings, 2L));
redisUtil.leftPush("tenant_created", tenantId);
// todo
return result.getData();
} else {
log.error("Client register failed: {}", result != null ? result.getMessage() : "Unknown error");
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound,
result != null ? result.getMessage() : "未知错误");
}
}
} catch (IOException e) {
log.error("Client register API error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, e.getMessage());
}
}
private ModelConfigDto buildModelConfig(Long tenantId, ModelTypeEnum type, Long id) {
ModelConfigDto modelConfigDto = new ModelConfigDto();
ModelConfigDto modelConfigDto1 = TenantFunctions
.callWithIgnoreCheck(() -> modelApplicationService.queryModelConfigById(id));
if (modelConfigDto1 == null) {
modelConfigDto.setId(id);
}
modelConfigDto.setSpaceId(-1L);
modelConfigDto.setIsReasonModel(YesOrNoEnum.N.getKey());
modelConfigDto.setApiProtocol(ModelApiProtocolEnum.OpenAI);
modelConfigDto.setScope(ModelConfig.ModelScopeEnum.Tenant);
modelConfigDto.setCreatorId(-1L);
modelConfigDto.setTenantId(tenantId);
modelConfigDto.setDescription("本模型由启明平台提供的试用模型每天最多免费提供100万token请尽快更换使用自有模型或各模型厂商api服务");
if (type == ModelTypeEnum.Chat) {
modelConfigDto.setName("DeepSeek V3");
modelConfigDto.setModel("deepseek-chat");
modelConfigDto.setType(ModelTypeEnum.Chat);
modelConfigDto.setFunctionCall(ModelFunctionCallEnum.StreamCallSupported);
} else if (type == ModelTypeEnum.Embeddings) {
modelConfigDto.setName("text-embedding-3-large");
modelConfigDto.setModel("text-embedding-3-large");
modelConfigDto.setType(ModelTypeEnum.Embeddings);
modelConfigDto.setFunctionCall(ModelFunctionCallEnum.Unsupported);
}
modelConfigDto.setStrategy(ModelConfig.ModelStrategyEnum.RoundRobin);
modelConfigDto.setMaxTokens(32000);
modelConfigDto.setTopP(0.7);
modelConfigDto.setTemperature(1.0);
modelConfigDto.setNetworkType(ModelConfig.NetworkType.Internet);
modelConfigDto.setDimension(1536);
ModelConfigDto.ApiInfo apiInfo = new ModelConfigDto.ApiInfo();
apiInfo.setUrl("https://openai-api.qiming.com/");
apiInfo.setKey("TENANT_SECRET");
apiInfo.setWeight(1);
modelConfigDto.setApiInfoList(List.of(apiInfo));
return modelConfigDto;
}
/**
* 验证客户端凭证
*
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 验证结果成功返回true失败返回false
*/
public boolean validateClientCredentials(String clientId, String clientSecret) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/secret/validate");
// 构建请求DTO
ClientValidateReqDTO reqDTO = new ClientValidateReqDTO();
reqDTO.setClientId(clientId);
reqDTO.setClientSecret(clientSecret);
// 构建请求体
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Verify client credential request failed, status: {}", response.code());
return false;
}
String responseBody = response.body().string();
ReqResult<Boolean> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<Boolean>>() {
});
// 判断验证是否成功
return result != null && result.isSuccess() && Boolean.TRUE.equals(result.getData());
}
} catch (IOException e) {
log.error("Server verify API error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed, e.getMessage());
}
}
/**
* 获取服务器配置详情
*
* @param uid 配置唯一标识
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 配置详情失败时返回null
*/
public ServerConfigDetailRespDTO getServerConfigDetail(String uid, String clientId, String clientSecret) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/config/detail");
// 构建请求DTO
ServerConfigDetailReqDTO reqDTO = new ServerConfigDetailReqDTO();
reqDTO.setUid(uid);
reqDTO.setClientId(clientId);
reqDTO.setClientSecret(clientSecret);
// 构建请求体
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送POST请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Get server config detail request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
"请求失败,状态码: " + response.code());
}
String responseBody = response.body().string();
ReqResult<ServerConfigDetailRespDTO> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<ServerConfigDetailRespDTO>>() {
});
if (result != null && result.isSuccess()) {
return result.getData();
} else {
log.error("Failed to get server config detail: {}", result != null ? result.getMessage() : "Unknown error");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
result != null ? result.getMessage() : "未知错误");
}
}
} catch (IOException e) {
log.error("Server config detail API error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed, e.getMessage());
}
}
/**
* 批量获取服务器配置详情
*
* @param uids 配置唯一标识列表
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 配置详情列表,失败时抛出异常
*/
public List<ServerConfigDetailRespDTO> getBatchServerConfigDetail(List<String> uids, String clientId,
String clientSecret) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/config/batchDetail");
// 构建请求DTO
ServerConfigBatchDetailReqDTO reqDTO = new ServerConfigBatchDetailReqDTO();
reqDTO.setUids(uids);
reqDTO.setClientId(clientId);
reqDTO.setClientSecret(clientSecret);
// 构建请求体
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送POST请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Batch get server config details request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
"请求失败,状态码: " + response.code());
}
String responseBody = response.body().string();
ReqResult<List<ServerConfigDetailRespDTO>> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<List<ServerConfigDetailRespDTO>>>() {
});
if (result != null && result.isSuccess()) {
return result.getData();
} else {
log.error("Batch get server config details failed: {}", result != null ? result.getMessage() : "Unknown error");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
result != null ? result.getMessage() : "未知错误");
}
}
} catch (IOException e) {
log.error("Exception calling batch server config detail API", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed, e.getMessage());
}
}
/**
* 批量获取服务器<b>审批</b>详情
*
* @param uids 配置唯一标识列表
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 配置详情列表,失败时抛出异常
*/
public List<ServerConfigDetailRespDTO> getBatchServerApproveDetail(List<String> uids, String clientId,
String clientSecret) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/config/batchApproveDetail");
// 构建请求DTO
ServerConfigBatchDetailReqDTO reqDTO = new ServerConfigBatchDetailReqDTO();
reqDTO.setUids(uids);
reqDTO.setClientId(clientId);
reqDTO.setClientSecret(clientSecret);
// 构建请求体
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送POST请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Batch get server config details request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
"请求失败,状态码: " + response.code());
}
String responseBody = response.body().string();
ReqResult<List<ServerConfigDetailRespDTO>> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<List<ServerConfigDetailRespDTO>>>() {
});
if (result != null && result.isSuccess()) {
return result.getData();
} else {
log.error("Batch get server config details failed: {}", result != null ? result.getMessage() : "Unknown error");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
result != null ? result.getMessage() : "未知错误");
}
}
} catch (IOException e) {
log.error("Exception calling batch server config detail API", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed, e.getMessage());
}
}
/**
* 保存服务器配置
*
* @param reqDTO 保存配置请求DTO
* @return 保存结果失败时返回null
*/
public <T> T saveServerConfig(ServerConfigSaveReqDTO reqDTO, Class<T> responseType) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/config/save");
// 构建请求体
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Save server config request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishConfigFailed,
"请求失败,状态码: " + response.code());
}
String responseBody = response.body().string();
ReqResult<Object> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<Object>>() {
});
if (result != null && result.isSuccess()) {
// 将结果转换为指定类型
return JSON.parseObject(JSON.toJSONString(result.getData()), responseType);
} else {
log.error("Save server config failed: {}", result != null ? result.getMessage() : "Unknown error");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishConfigFailed,
result != null ? result.getMessage() : "未知错误");
}
}
} catch (IOException e) {
log.error("Server save config API error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishConfigFailed, e.getMessage());
}
}
/**
* 下线服务器配置
* 服务器端接口对应 EcoMarketServerConfigController 中的 offline 方法
*
* @param uid 配置UID
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 操作成功返回true失败返回false
*/
public boolean offlineServerConfig(String uid, String clientId, String clientSecret) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/config/offline");
// 构建请求体使用DTO对象
ServerConfigOfflineReqDTO reqDTO = new ServerConfigOfflineReqDTO();
reqDTO.setUid(uid);
reqDTO.setClientId(clientId);
reqDTO.setClientSecret(clientSecret);
// 将DTO对象转换为JSON
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Offline server config request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketOfflineConfigFailed,
"请求失败,状态码: " + response.code());
}
var responseBodyObj = response.body();
if (responseBodyObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketConfigResultBodyEmpty);
}
String responseBody = responseBodyObj.string();
ReqResult<Void> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<Void>>() {
});
// 判断请求是否成功
return result != null && result.isSuccess();
}
} catch (IOException e) {
log.error("Server offline config API error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketOfflineConfigFailed, e.getMessage());
}
}
/**
* 撤销发布服务器配置
* 服务器端接口对应 EcoMarketServerConfigController 中的 offline 方法
*
* @param uid 配置UID
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 操作成功返回true失败返回false
*/
public boolean unpublishServerConfig(String uid, String clientId, String clientSecret) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/config/unpublish");
// 构建请求体使用DTO对象
ServerConfigUnpublishReqDTO reqDTO = new ServerConfigUnpublishReqDTO();
reqDTO.setUid(uid);
reqDTO.setClientId(clientId);
reqDTO.setClientSecret(clientSecret);
// 将DTO对象转换为JSON
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Revoke publish server config request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketOfflineConfigFailed,
"请求失败,状态码: " + response.code());
}
var responseBodyObj = response.body();
if (responseBodyObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketConfigResultBodyEmpty);
}
String responseBody = responseBodyObj.string();
ReqResult<Void> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<Void>>() {
});
return result != null && result.isSuccess();
}
} catch (IOException e) {
log.error("Server revoke publish API error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketOfflineConfigFailed, e.getMessage());
}
}
/**
* 查询配置状态
*
* @param uid 配置UID
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 状态信息失败时返回null
*/
public Map<String, Object> getConfigStatus(String uid, String clientId, String clientSecret) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/config/status");
// 构建请求DTO
ServerConfigStatusReqDTO reqDTO = new ServerConfigStatusReqDTO();
reqDTO.setUid(uid);
reqDTO.setClientId(clientId);
reqDTO.setClientSecret(clientSecret);
// 构建请求体
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Query config status request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketQueryConfigStatusFailed,
"请求失败,状态码: " + response.code());
}
var responseBodyObj = response.body();
if (responseBodyObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketConfigResultBodyEmpty);
}
String responseBody = responseBodyObj.string();
ReqResult<Map<String, Object>> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<Map<String, Object>>>() {
});
if (result != null && result.isSuccess()) {
return result.getData();
} else {
log.error("Query config status failed: {}", result != null ? result.getMessage() : "Unknown error");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketQueryConfigStatusFailed,
result != null ? result.getMessage() : "未知错误");
}
}
} catch (IOException e) {
log.error("Server query config status API error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketQueryConfigStatusFailed, e.getMessage());
}
}
/**
* 保存并直接发布服务器配置
* 服务器端接口对应 EcoMarketServerConfigController 中的 saveAndPublish 方法
*
* @param reqDTO 保存配置请求DTO
* @param responseType 响应类型
* @return 保存并发布结果失败时返回null
*/
public <T> T saveAndPublishServerConfig(ServerConfigSaveReqDTO reqDTO, Class<T> responseType) {
try {
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/config/saveAndPublish");
// 构建请求体
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
// 发送请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Save-and-publish server config request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishConfigFailed,
"请求失败,状态码: " + response.code());
}
var responseBodyObj = response.body();
if (responseBodyObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketConfigResultBodyEmpty);
}
String responseBody = responseBodyObj.string();
log.debug("Server response body: {}", responseBody);
// 使用Fastjson2解析响应
ReqResult<Object> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<Object>>() {
});
if (result != null && result.isSuccess()) {
// 将结果转换为指定类型
return JSON.parseObject(JSON.toJSONString(result.getData()), responseType);
} else {
log.error("Save-and-publish server config failed: {}", result != null ? result.getMessage() : "Unknown error");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishConfigFailed,
result != null ? result.getMessage() : "未知错误");
}
}
} catch (IOException e) {
log.error("Server save-and-publish API error", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishConfigFailed, e.getMessage());
}
}
/**
* 分页查询服务器配置列表
* 服务器端接口对应 EcoMarketServerConfigController 中的 list 方法
*
* @param reqDTO 查询请求DTO
* @return 分页查询结果
*/
public SuperPage<ServerConfigListRespDTO> queryServerConfigList(PageQueryVo<ServerConfigQueryRequest> reqDTO) {
try {
log.info("Server config list query: reqDTO={}", reqDTO);
String url = buildApiUrl(EcoMarketApiConstant.SERVER_API_BASE + "/config/list");
// 构建请求体
String jsonBody = JSON.toJSONString(reqDTO);
RequestBody body = RequestBody.create(jsonBody, JSON_MEDIA_TYPE);
// 构建请求,添加客户端凭证到请求头
Request.Builder requestBuilder = new Request.Builder()
.url(url)
.post(body);
Request request = requestBuilder.build();
// 发送请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Query server config list request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
"状态码: " + response.code());
}
var responseBodyObj = response.body();
if (responseBodyObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketConfigResultBodyEmpty);
}
String responseBody = responseBodyObj.string();
// 使用Fastjson2解析带泛型的分页结果
ReqResult<IPage<ServerConfigListRespDTO>> result = JSON.parseObject(
responseBody,
new TypeReference<ReqResult<IPage<ServerConfigListRespDTO>>>() {
});
if (result == null || !result.isSuccess()) {
log.error("Query server config list failed: errorCode={}, errorMsg={}",
result != null ? result.getCode() : "NULL",
result != null ? result.getMessage() : "查询失败");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
result != null ? result.getMessage() : "查询服务器配置失败");
}
var superPage = SuperPage.build(result.getData(), result.getData().getRecords());
return superPage;
}
} catch (IOException e) {
log.error("Exception calling server config list API", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketCenterUpgrading);
}
}
/**
* 查询自动租户启用的配置信息
* 服务器端接口对应 EcoMarketServerConfigController 中的 autoUse 方法
*
* @param reqDTO 查询请求DTO
* @return 分页查询结果
*/
public List<ServerConfigDetailRespDTO> queryAutoUseConfigList() {
try {
log.info("Query auto tenant enable configs");
String url = buildApiUrl("/api/system/eco/market/server/autoUse/autoUseList");
// 构建请求,添加客户端凭证到请求头
RequestBody body = RequestBody.create("", JSON_MEDIA_TYPE);
Request.Builder requestBuilder = new Request.Builder()
.url(url)
.post(body);
Request request = requestBuilder.build();
// 发送请求
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Query server config list request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
"状态码: " + response.code());
}
var responseBodyObj = response.body();
if (responseBodyObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketConfigResultBodyEmpty);
}
String responseBody = responseBodyObj.string();
// 使用Fastjson2解析带泛型的分页结果
ReqResult<List<ServerConfigDetailRespDTO>> result = JSON.parseObject(
responseBody,
new TypeReference<ReqResult<List<ServerConfigDetailRespDTO>>>() {
});
if (result == null || !result.isSuccess()) {
log.error("Query server config list failed: errorCode={}, errorMsg={}",
result != null ? result.getCode() : "NULL",
result != null ? result.getMessage() : "查询失败");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketGetConfigFailed,
result != null ? result.getMessage() : "查询服务器配置失败");
}
return result.getData();
}
} catch (IOException e) {
log.error("Exception calling server config list API", e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketCenterUpgrading);
}
}
/**
* 上传页面zip包到服务器端
*
* @param fileBytes 文件字节数组
* @param fileName 文件名
* @param contentType 文件类型
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 上传成功后的文件URL失败时抛出异常
*/
public String uploadPageZip(byte[] fileBytes, String fileName, String contentType,
String clientId, String clientSecret) {
try {
String url = buildApiUrl(EcoMarketApiConstant.ServerConfig.UPLOAD_PAGE_ZIP);
log.info("Upload page zip to server: fileName={}, size={}, contentType={}", fileName, fileBytes.length, contentType);
MediaType fileMediaType = MediaType.parse(contentType != null ? contentType : "application/octet-stream");
RequestBody fileBody = RequestBody.create(fileBytes, fileMediaType);
// 构建multipart/form-data请求体
MultipartBody.Builder multipartBuilder = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", fileName, fileBody)
.addFormDataPart("fileName", fileName)
.addFormDataPart("clientId", clientId)
.addFormDataPart("clientSecret", clientSecret);
RequestBody requestBody = multipartBuilder.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
try (Response response = httpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
log.error("Upload file to server request failed, status: {}", response.code());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageExportFailed, "上传文件失败,状态码: " + response.code());
}
var responseBodyObj = response.body();
if (responseBodyObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketConfigResultBodyEmpty);
}
String responseBody = responseBodyObj.string();
ReqResult<String> result = JSON.parseObject(responseBody,
new TypeReference<ReqResult<String>>() {
});
if (result != null && result.isSuccess()) {
String fileUrl = result.getData();
log.info("Page zip upload OK: fileName={}, url={}", fileName, fileUrl);
return fileUrl;
} else {
log.error("Page zip upload to server failed: {}", result != null ? result.getMessage() : "Unknown error");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageExportFailed,
result != null ? result.getMessage() : "上传页面zip包失败");
}
}
} catch (IOException e) {
log.error("Server page zip upload API error: fileName={}", fileName, e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageExportFailed, "上传页面zip包失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,43 @@
package com.xspaceagi.eco.market.domain.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* 生态市场配置类
*/
@Slf4j
@Configuration
@EnableConfigurationProperties(EcoMarketProperties.class)
public class EcoMarketConfig {
private final EcoMarketProperties ecoMarketProperties;
public EcoMarketConfig(EcoMarketProperties ecoMarketProperties) {
this.ecoMarketProperties = ecoMarketProperties;
log.info("Eco-market config loaded, server URL: {}",
ecoMarketProperties.getServer().getBaseUrl());
}
/**
* 配置RestTemplate用于服务调用
*
* @return RestTemplate实例
*/
@Bean
public RestTemplate ecoMarketRestTemplate() {
return new RestTemplate();
}
/**
* 获取服务器基础URL
*
* @return 服务器基础URL
*/
public String getServerBaseUrl() {
return ecoMarketProperties.getServer().getBaseUrl();
}
}

View File

@@ -0,0 +1,63 @@
package com.xspaceagi.eco.market.domain.config;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import com.xspaceagi.system.spec.utils.MySpringBeanContextUtil;
/**
* 生态市场配置工具类
* 提供静态方法访问生态市场配置
*/
@Component
@DependsOn({"ecoMarketConfig", "ecoMarketProperties"})
public class EcoMarketConfigUtils {
/**
* 获取生态市场配置
*
* @return 生态市场配置
* @throws IllegalStateException 如果ApplicationContext未初始化
*/
public static EcoMarketConfig getEcoMarketConfig() {
return MySpringBeanContextUtil.get(EcoMarketConfig.class);
}
/**
* 获取生态市场属性
*
* @return 生态市场属性
* @throws IllegalStateException 如果ApplicationContext未初始化
*/
public static EcoMarketProperties getEcoMarketProperties() {
return MySpringBeanContextUtil.get(EcoMarketProperties.class);
}
/**
* 获取服务器基础URL
*
* @return 服务器基础URL
* @throws IllegalStateException 如果ApplicationContext未初始化
*/
public static String getServerBaseUrl() {
return getEcoMarketConfig().getServerBaseUrl();
}
/**
* 构建完整的API URL
*
* @param apiPath API路径
* @return 完整的API URL
* @throws IllegalStateException 如果ApplicationContext未初始化
*/
public static String buildApiUrl(String apiPath) {
String baseUrl = getServerBaseUrl();
if (baseUrl.endsWith("/")) {
baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
}
if (apiPath.startsWith("/")) {
apiPath = apiPath.substring(1);
}
return baseUrl + "/" + apiPath;
}
}

View File

@@ -0,0 +1,31 @@
package com.xspaceagi.eco.market.domain.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 生态市场配置属性
* 对应 application.yml 中的 eco-market 配置
*/
@Data
@Component
@ConfigurationProperties(prefix = "eco-market")
public class EcoMarketProperties {
/**
* 服务端配置
*/
private ServerConfig server = new ServerConfig();
/**
* 服务端配置
*/
@Data
public static class ServerConfig {
/**
* 远程服务器基础URL
*/
private String baseUrl;
}
}

View File

@@ -0,0 +1,38 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* 客户端注册请求DTO
*/
@Data
@Schema(description = "客户端注册请求DTO")
public class ClientRegisterReqDTO {
/**
* 名称
*/
@NotBlank(message = "Name is required")
@Schema(description = "名称", required = true)
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 租户ID非必填如不填则使用当前用户的租户ID
*/
@Schema(description = "租户ID非必填如不填则使用当前用户的租户ID")
private Long tenantId;
/**
* 客户端ID
*/
@Schema(description = "客户端ID")
private String clientId;
}

View File

@@ -0,0 +1,34 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 客户端注册请求
*/
@Data
@Schema(description = "客户端注册请求")
public class ClientRegisterRequest {
/**
* 名称
*/
@NotBlank(message = "Name is required")
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 租户ID
*/
@NotNull(message = "Tenant ID is required")
@Schema(description = "租户ID", requiredMode = Schema.RequiredMode.REQUIRED)
private Long tenantId;
}

View File

@@ -0,0 +1,18 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(description = "客户端验证请求DTO")
public class ClientValidateReqDTO {
@Schema(description = "客户端ID")
@NotBlank(message = "clientId is required")
private String clientId;
@Schema(description = "客户端密钥")
@NotBlank(message = "clientSecret is required")
private String clientSecret;
}

View File

@@ -0,0 +1,30 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Data
@Schema(description = "配置审批请求DTO")
public class ServerConfigApproveReqDTO {
@Schema(description = "配置UID")
@NotBlank(message = "Configuration UID is required")
private String uid;
@Schema(description = "是否批准")
@NotNull(message = "Approval status is required")
private Boolean approved;
// @Schema(description = "客户端ID")
// @NotBlank(message = "clientId is required")
// private String clientId;
// @Schema(description = "客户端密钥")
// @NotBlank(message = "clientSecret is required")
// private String clientSecret;
}

View File

@@ -0,0 +1,34 @@
package com.xspaceagi.eco.market.domain.dto.req;
import java.util.List;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
/**
* 服务器配置批量详情查询请求DTO
*/
@Data
@Schema(description = "服务器配置批量详情查询请求DTO")
public class ServerConfigBatchDetailReqDTO {
/**
* 配置UID列表
*/
@NotEmpty(message = "UID list cannot be empty")
@Schema(description = "配置UID列表", required = true)
private List<String> uids;
/**
* 客户端ID
*/
@Schema(description = "客户端ID")
private String clientId;
/**
* 客户端密钥
*/
@Schema(description = "客户端密钥")
private String clientSecret;
}

View File

@@ -0,0 +1,32 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
/**
* 服务器配置详情查询请求DTO
*/
@Data
@Schema(description = "服务器配置详情查询请求DTO")
public class ServerConfigDetailReqDTO {
/**
* 配置UID
*/
@NotBlank(message = "UID is required")
@Schema(description = "配置UID", required = true)
private String uid;
/**
* 客户端ID
*/
@Schema(description = "客户端ID")
private String clientId;
/**
* 客户端密钥
*/
@Schema(description = "客户端密钥")
private String clientSecret;
}

View File

@@ -0,0 +1,22 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(description = "配置下线请求DTO")
public class ServerConfigOfflineReqDTO {
@Schema(description = "配置UID")
@NotBlank(message = "Configuration UID is required")
private String uid;
@Schema(description = "客户端ID")
@NotBlank(message = "clientId is required")
private String clientId;
@Schema(description = "客户端密钥")
@NotBlank(message = "clientSecret is required")
private String clientSecret;
}

View File

@@ -0,0 +1,22 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(description = "发布配置详情请求DTO")
public class ServerConfigPublishDetailReqDTO {
@Schema(description = "配置唯一标识")
@NotBlank(message = "uid is required")
private String uid;
@Schema(description = "客户端ID")
@NotBlank(message = "clientId is required")
private String clientId;
@Schema(description = "客户端密钥")
@NotBlank(message = "clientSecret is required")
private String clientSecret;
}

View File

@@ -0,0 +1,22 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(description = "配置发布请求DTO")
public class ServerConfigPublishReqDTO {
@Schema(description = "配置UID")
@NotBlank(message = "Configuration UID is required")
private String uid;
@Schema(description = "客户端ID")
@NotBlank(message = "clientId is required")
private String clientId;
@Schema(description = "客户端密钥")
@NotBlank(message = "clientSecret is required")
private String clientSecret;
}

View File

@@ -0,0 +1,60 @@
package com.xspaceagi.eco.market.domain.dto.req;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 服务器配置查询请求DTO
*/
@Data
@Schema(description = "服务器配置查询请求DTO")
public class ServerConfigQueryRequest {
/**
* 名称,模糊查询
*/
@Schema(description = "名称,模糊查询")
private String name;
/**
* 细分类型,比如: 插件,智能体,工作流
* @see Published.TargetType
*/
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
private String targetSubType;
/**
* 市场类型,1:插件;2:模板;3:MCP
*/
@Schema(description = "市场类型,1:插件;2:模板;3:MCP")
@NotNull(message = "Market type is required")
private Integer dataType;
/**
* tab类型: 1: 全部; 2: 启用的;3:我的分享; 默认全部
* @see EcoMarketSubTabType
*/
@Schema(description = "tab类型: 1: 全部; 2: 启用的;3:我的分享;")
private Integer subTabType;
/**
* 分类编码
*/
@Schema(description = "分类编码")
private String categoryCode;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
@Schema(description = "分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回")
private Integer shareStatus;
}

View File

@@ -0,0 +1,128 @@
package com.xspaceagi.eco.market.domain.dto.req;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 服务器配置保存请求DTO
*/
@Data
@Schema(description = "服务器配置保存请求DTO")
public class ServerConfigSaveReqDTO {
/**
* ID,新增时为空,更新时必填
*/
@Schema(description = "ID,新增时为空,更新时必填")
private Long id;
@NotBlank(message = "Unique identifier is required")
@Schema(description = "唯一标识", requiredMode = Schema.RequiredMode.REQUIRED)
private String uid;
/**
* 名称
*/
@NotBlank(message = "Name is required")
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED)
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
@NotNull(message = "Market type is required")
@Schema(description = "市场类型,默认插件,1:插件;2:模板;3:MCP", requiredMode = Schema.RequiredMode.REQUIRED)
private Integer dataType;
/**
* 细分类型,比如: 插件,智能体,工作流
*/
@Schema(description = "细分类型,比如: 插件,智能体,工作流")
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
@Schema(description = "子类型")
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
@Schema(description = "具体目标的id,可以智能体,工作流,插件,还有mcp等")
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
@Schema(description = "分类编码,商业服务等,通过接口获取")
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
@Schema(description = "分类名称,商业服务等,通过接口获取")
private String categoryName;
/**
* 作者信息
*/
@Schema(description = "作者信息")
private String author;
/**
* 发布文档
*/
@Schema(description = "发布文档")
private String publishDoc;
/**
* 请求参数配置json
*/
@Schema(description = "请求参数配置json")
private String configParamJson;
/**
* 配置json,存储插件的配置信息如果有其他额外的信息保存放这里
*/
@Schema(description = "配置json,存储插件的配置信息如果有其他额外的信息保存放这里")
private String configJson;
/**
* 图标图片地址
*/
@Schema(description = "图标图片地址")
private String icon;
/**
* 客户端ID
*/
@NotBlank(message = "Client ID is required")
@Schema(description = "客户端ID", requiredMode = Schema.RequiredMode.REQUIRED)
private String clientId;
/**
* 客户端密钥
*/
@NotBlank(message = "Client secret is required")
@Schema(description = "客户端密钥", requiredMode = Schema.RequiredMode.REQUIRED)
private String clientSecret;
/**
* 页面压缩包地址
*/
@Schema(description = "页面压缩包地址")
private String pageZipUrl;
}

View File

@@ -0,0 +1,22 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(description = "配置状态查询请求DTO")
public class ServerConfigStatusReqDTO {
@Schema(description = "配置唯一标识")
@NotBlank(message = "uid is required")
private String uid;
@Schema(description = "客户端ID")
@NotBlank(message = "clientId is required")
private String clientId;
@Schema(description = "客户端密钥")
@NotBlank(message = "clientSecret is required")
private String clientSecret;
}

View File

@@ -0,0 +1,22 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
@Schema(description = "配置撤销发布请求DTO")
public class ServerConfigUnpublishReqDTO {
@Schema(description = "配置UID")
@NotBlank(message = "Configuration UID is required")
private String uid;
@Schema(description = "客户端ID")
@NotBlank(message = "clientId is required")
private String clientId;
@Schema(description = "客户端密钥")
@NotBlank(message = "clientSecret is required")
private String clientSecret;
}

View File

@@ -0,0 +1,54 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 服务器发布配置查询请求DTO
*/
@Data
@Schema(description = "服务器发布配置查询请求DTO")
public class ServerPublishConfigQueryRequest {
/**
* 名称,模糊查询
*/
@Schema(description = "名称,模糊查询")
private String name;
/**
* 市场类型,1:插件;2:模板;3:MCP
*/
@Schema(description = "市场类型,1:插件;2:模板;3:MCP")
private Integer dataType;
/**
* 细分类型,比如: 插件,智能体,工作流
*/
@Schema(description = "细分类型,比如: 插件,智能体,工作流")
private String targetType;
/**
* 分类编码
*/
@Schema(description = "分类编码")
private String categoryCode;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
@Schema(description = "分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回")
private Integer shareStatus;
/**
* 使用状态,1:启用;2:禁用;
*/
@Schema(description = "使用状态,1:启用;2:禁用;")
private Integer useStatus;
/**
* 作者信息,模糊查询
*/
@Schema(description = "作者信息,模糊查询")
private String author;
}

View File

@@ -0,0 +1,31 @@
package com.xspaceagi.eco.market.domain.dto.req;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 更新并启用配置请求DTO
*/
@Data
@Schema(description = "更新并启用配置请求DTO")
public class UpdateAndEnableConfigReqDTO {
/**
* 配置唯一标识
*/
@Schema(description = "配置唯一标识", requiredMode = Schema.RequiredMode.REQUIRED)
private String uid;
/**
* 配置参数JSON
*/
@Schema(description = "配置参数JSON", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private String configParamJson;
/**
* 配置json,存储插件的配置信息如果有其他额外的信息保存放这里
*/
@Schema(description = "配置json,存储插件的配置信息如果有其他额外的信息保存放这里", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
private String configJson;
}

View File

@@ -0,0 +1,54 @@
package com.xspaceagi.eco.market.domain.dto.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 客户端注册响应DTO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "客户端注册响应DTO")
public class ClientRegisterRespDTO {
/**
* 主键id
*/
@Schema(description = "主键id")
private Long id;
/**
* 名称
*/
@Schema(description = "名称")
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 客户端ID
*/
@Schema(description = "客户端ID")
private String clientId;
/**
* 客户端密钥
*/
@Schema(description = "客户端密钥")
private String clientSecret;
/**
* 租户ID
*/
@Schema(description = "租户ID")
private Long tenantId;
}

View File

@@ -0,0 +1,65 @@
package com.xspaceagi.eco.market.domain.dto.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 客户端密钥响应DTO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "客户端密钥响应DTO")
public class ClientSecretRespDTO {
/**
* 主键ID
*/
@Schema(description = "主键ID")
private Long id;
/**
* 名称
*/
@Schema(description = "名称")
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 客户端ID
*/
@Schema(description = "客户端ID")
private String clientId;
/**
* 客户端密钥
*/
@Schema(description = "客户端密钥")
private String clientSecret;
/**
* 租户ID
*/
@Schema(description = "租户ID")
private Long tenantId;
/**
* 创建时间
*/
@Schema(description = "创建时间")
private LocalDateTime created;
}

View File

@@ -0,0 +1,229 @@
package com.xspaceagi.eco.market.domain.dto.resp;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 服务器配置响应DTO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "服务器配置响应DTO,包含配置json信息")
public class ServerConfigDetailRespDTO {
/**
* 主键id
*/
@Schema(description = "主键id")
private Long id;
/**
* 唯一ID,分布式唯一UUID
*/
@Schema(description = "唯一ID,分布式唯一UUID")
private String uid;
/**
* 名称
*/
@Schema(description = "名称")
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
@Schema(description = "市场类型,默认插件,1:插件;2:模板;3:MCP")
private Integer dataType;
/**
* 市场类型名称
*/
@Schema(description = "市场类型名称")
private String dataTypeName;
/**
* 细分类型,比如: 插件,智能体,工作流
*/
@Schema(description = "细分类型,比如: 插件,智能体,工作流")
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
@Schema(description = "子类型")
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
@Schema(description = "具体目标的id,可以智能体,工作流,插件,还有mcp等")
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
@Schema(description = "分类编码,商业服务等,通过接口获取")
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
@Schema(description = "分类名称,商业服务等,通过接口获取")
private String categoryName;
/**
* 是否我的分享,0:否(生态市场获取的);1:是(我的分享)
*/
@Schema(description = "是否我的分享,0:否(生态市场获取的);1:是(我的分享)")
private Integer ownedFlag;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
@Schema(description = "分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回")
private Integer shareStatus;
/**
* 分享状态名称
*/
@Schema(description = "分享状态名称")
private String shareStatusName;
/**
* 使用状态,1:启用;2:禁用;
*/
@Schema(description = "使用状态,1:启用;2:禁用;")
private Integer useStatus;
/**
* 使用状态名称
*/
@Schema(description = "使用状态名称")
private String useStatusName;
/**
* 发布时间
*/
@Schema(description = "发布时间")
private LocalDateTime publishTime;
/**
* 下线时间
*/
@Schema(description = "下线时间")
private LocalDateTime offlineTime;
/**
* 版本号,自增,发布一次增加1,初始值为1
*/
@Schema(description = "版本号,自增,发布一次增加1,初始值为1")
private Long versionNumber;
/**
* 作者信息
*/
@Schema(description = "作者信息")
private String author;
/**
* 发布文档
*/
@Schema(description = "发布文档")
private String publishDoc;
/**
* 图标图片地址
*/
@Schema(description = "图标图片地址")
private String icon;
/**
* 审批信息
*/
@Schema(description = "审批信息")
private String approveMessage;
/**
* 请求参数配置json
*/
private String configParamJson;
/**
* 配置json,存储插件的配置信息如果有其他额外的信息保存放这里
*/
private String configJson;
/**
* 租户ID
*/
@Schema(description = "租户ID")
private Long tenantId;
/**
* 所属空间ID
*/
@Schema(description = "所属空间ID")
private Long spaceId;
/**
* 创建者的客户端ID
*/
@Schema(description = "创建者的客户端ID")
private String createClientId;
/**
* 创建时间
*/
@Schema(description = "创建时间")
private LocalDateTime created;
/**
* 创建人id
*/
@Schema(description = "创建人id")
private Long creatorId;
/**
* 创建人
*/
@Schema(description = "创建人")
private String creatorName;
/**
* 更新时间
*/
@Schema(description = "更新时间")
private LocalDateTime modified;
/**
* 最后修改人id
*/
@Schema(description = "最后修改人id")
private Long modifiedId;
/**
* 最后修改人
*/
@Schema(description = "最后修改人")
private String modifiedName;
@Schema(description = "页面压缩包地址")
private String pageZipUrl;
}

View File

@@ -0,0 +1,210 @@
package com.xspaceagi.eco.market.domain.dto.resp;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* 服务器配置响应DTO,去掉的配置json信息
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "服务器配置响应DTO,去掉的配置json信息")
public class ServerConfigListRespDTO {
/**
* 主键id
*/
@Schema(description = "主键id")
private Long id;
/**
* 唯一ID,分布式唯一UUID
*/
@Schema(description = "唯一ID,分布式唯一UUID")
private String uid;
/**
* 名称
*/
@Schema(description = "名称")
private String name;
/**
* 描述
*/
@Schema(description = "描述")
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
@Schema(description = "市场类型,默认插件,1:插件;2:模板;3:MCP")
private Integer dataType;
/**
* 市场类型名称
*/
@Schema(description = "市场类型名称")
private String dataTypeName;
/**
* 细分类型,比如: 插件,智能体,工作流
*/
@Schema(description = "细分类型,比如: 插件,智能体,工作流")
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
@Schema(description = "子类型")
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
@Schema(description = "具体目标的id,可以智能体,工作流,插件,还有mcp等")
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
@Schema(description = "分类编码,商业服务等,通过接口获取")
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
@Schema(description = "分类名称,商业服务等,通过接口获取")
private String categoryName;
/**
* 是否我的分享,0:否(生态市场获取的);1:是(我的分享)
*/
@Schema(description = "是否我的分享,0:否(生态市场获取的);1:是(我的分享)")
private Integer ownedFlag;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
@Schema(description = "分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回")
private Integer shareStatus;
/**
* 分享状态名称
*/
@Schema(description = "分享状态名称")
private String shareStatusName;
/**
* 使用状态,1:启用;2:禁用;
*/
@Schema(description = "使用状态,1:启用;2:禁用;")
private Integer useStatus;
/**
* 使用状态名称
*/
@Schema(description = "使用状态名称")
private String useStatusName;
/**
* 发布时间
*/
@Schema(description = "发布时间")
private LocalDateTime publishTime;
/**
* 下线时间
*/
@Schema(description = "下线时间")
private LocalDateTime offlineTime;
/**
* 版本号,自增,发布一次增加1,初始值为1
*/
@Schema(description = "版本号,自增,发布一次增加1,初始值为1")
private Long versionNumber;
/**
* 作者信息
*/
@Schema(description = "作者信息")
private String author;
/**
* 发布文档
*/
@Schema(description = "发布文档")
private String publishDoc;
/**
* 图标图片地址
*/
@Schema(description = "图标图片地址")
private String icon;
/**
* 租户ID
*/
@Schema(description = "租户ID")
private Long tenantId;
/**
* 所属空间ID
*/
@Schema(description = "所属空间ID")
private Long spaceId;
/**
* 创建者的客户端ID
*/
@Schema(description = "创建者的客户端ID")
private String createClientId;
/**
* 创建时间
*/
@Schema(description = "创建时间")
private LocalDateTime created;
/**
* 创建人id
*/
@Schema(description = "创建人id")
private Long creatorId;
/**
* 创建人
*/
@Schema(description = "创建人")
private String creatorName;
/**
* 更新时间
*/
@Schema(description = "更新时间")
private LocalDateTime modified;
/**
* 最后修改人id
*/
@Schema(description = "最后修改人id")
private Long modifiedId;
/**
* 最后修改人
*/
@Schema(description = "最后修改人")
private String modifiedName;
}

View File

@@ -0,0 +1,230 @@
package com.xspaceagi.eco.market.domain.model;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableField;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import com.xspaceagi.custompage.sdk.dto.SourceTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.ibatis.type.EnumTypeHandler;
/**
* 生态市场配置
*
* @TableName eco_market_client_config
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EcoMarketClientConfigModel {
/**
* 主键id
*/
private Long id;
/**
* 唯一ID,分布式唯一UUID
*/
private String uid;
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
private Integer dataType;
/**
* 细分类型,比如: 插件,智能体,工作流
*
* @see Published.TargetType
*/
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
private String categoryName;
/**
* 是否我的分享,0:否(生态市场获取的);1:是(我的分享)
*/
private Integer ownedFlag;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
private Integer shareStatus;
/**
* 使用状态,1:启用;2:禁用;
*/
private Integer useStatus;
/**
* 发布时间
*/
private LocalDateTime publishTime;
/**
* 下线时间
*/
private LocalDateTime offlineTime;
/**
* 版本号,自增,发布一次增加1,初始值为1
*/
private Long versionNumber;
/**
* 作者信息
*/
private String author;
/**
* 发布文档
*/
private String publishDoc;
/**
* 请求参数配置json,生态市场拉取的最新的配置,或者本地保存的配置;
* <p> 因为有的数据,是从生态市场拉取的,本地没有,所以这个字段给前端使用,是多重含义 </p>
*/
private String configParamJson;
/**
* 当前本地的原始配置
*/
private String localConfigParamJson;
/**
* 服务器配置参数json,存储服务器配置的参数信息
*/
private String serverConfigParamJson;
/**
* 配置json,存储插件的配置信息如果有其他额外的信息保存放这里
*/
private String configJson;
/**
* 当前本地的原始配置json
*/
@Schema(description = "当前本地的原始配置json")
private String localConfigJson;
/**
* 服务器配置json
*/
@Schema(description = "服务器配置json")
private String serverConfigJson;
/**
* 图标图片地址
*/
private String icon;
/**
* 审批信息
*/
private String approveMessage;
/**
* 是否租户自动启用插件,1:租户自动启用;0:非租户自动启用
*/
private Boolean tenantEnabled;
/**
* 租户ID
*/
private Long tenantId;
/**
* 创建者的客户端ID
*/
private String createClientId;
/**
* 创建时间
*/
private LocalDateTime created;
/**
* 创建人id
*/
private Long creatorId;
/**
* 创建人
*/
private String creatorName;
/**
* 更新时间
*/
private LocalDateTime modified;
/**
* 最后修改人id
*/
private Long modifiedId;
/**
* 最后修改人
*/
private String modifiedName;
// ======== 下面是扩展字段======
/**
* 是否是新版本
*/
private Boolean isNewVersion;
/**
* 服务器版本号 ,serverVersionNumber 和 client端的 versionNumber 比较,如果serverVersionNumber
* > versionNumber,则isNewVersion为true
*/
private Long serverVersionNumber;
/**
* 页面压缩包地址
*/
private String pageZipUrl;
private String coverImg;
private SourceTypeEnum coverImgSourceType;
}

View File

@@ -0,0 +1,230 @@
package com.xspaceagi.eco.market.domain.model;
import java.time.LocalDateTime;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* 生态市场,客户端,已发布配置
*
* @TableName eco_market_client_publish_config
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EcoMarketClientPublishConfigModel {
/**
* 主键id
*/
private Long id;
/**
* 唯一ID,分布式唯一UUID
*/
private String uid;
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
private Integer dataType;
/**
* 细分类型,比如: 插件,智能体,工作流
*
* @see Published.TargetType
*/
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
private String categoryName;
/**
* 是否我的分享,0:否(生态市场获取的);1:是(我的分享)
*/
private Integer ownedFlag;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
private Integer shareStatus;
/**
* 使用状态,1:启用;2:禁用;
*/
private Integer useStatus;
/**
* 发布时间
*/
private LocalDateTime publishTime;
/**
* 下线时间
*/
private LocalDateTime offlineTime;
/**
* 版本号,自增,发布一次增加1,初始值为1
*/
private Long versionNumber;
/**
* 作者信息
*/
private String author;
/**
* 发布文档
*/
private String publishDoc;
/**
* 请求参数配置json
*/
private String configParamJson;
/**
* 配置json,存储插件的配置信息如果有其他额外的信息保存放这里
*/
private String configJson;
/**
* 图标图片地址
*/
private String icon;
/**
* 审批信息
*/
private String approveMessage;
/**
* 是否租户自动启用插件,1:租户自动启用;0:非租户自动启用
*/
private Boolean tenantEnabled;
/**
* 租户ID
*/
private Long tenantId;
/**
* 创建者的客户端ID
*/
private String createClientId;
/**
* 创建时间
*/
private LocalDateTime created;
/**
* 创建人id
*/
private Long creatorId;
/**
* 创建人
*/
private String creatorName;
/**
* 更新时间
*/
private LocalDateTime modified;
/**
* 最后修改人id
*/
private Long modifiedId;
/**
* 最后修改人
*/
private String modifiedName;
/**
* 页面压缩包地址
*/
private String pageZipUrl;
public static EcoMarketClientConfigModel toClientConfigModel(EcoMarketClientPublishConfigModel model) {
if (model == null) {
return null;
}
return EcoMarketClientConfigModel.builder()
.id(model.getId())
.uid(model.getUid())
.name(model.getName())
.description(model.getDescription())
.dataType(model.getDataType())
.targetType(model.getTargetType())
.targetSubType(model.getTargetSubType())
.targetId(model.getTargetId())
.categoryCode(model.getCategoryCode())
.categoryName(model.getCategoryName())
.ownedFlag(model.getOwnedFlag())
.shareStatus(model.getShareStatus())
.useStatus(model.getUseStatus())
.publishTime(model.getPublishTime())
.offlineTime(model.getOfflineTime())
.versionNumber(model.getVersionNumber())
.author(model.getAuthor())
.publishDoc(model.getPublishDoc())
.configParamJson(model.getConfigParamJson())
.localConfigParamJson(model.configParamJson)
.serverConfigParamJson(null)
.configJson(model.getConfigJson())
.icon(model.getIcon())
.tenantId(model.getTenantId())
.createClientId(model.getCreateClientId())
.created(model.getCreated())
.creatorId(model.getCreatorId())
.creatorName(model.getCreatorName())
.modified(model.getModified())
.modifiedId(model.getModifiedId())
.modifiedName(model.getModifiedName())
.isNewVersion(false)
.serverVersionNumber(null)
.pageZipUrl(model.getPageZipUrl())
.build();
}
}

View File

@@ -0,0 +1,86 @@
package com.xspaceagi.eco.market.domain.model;
import com.xspaceagi.eco.market.sdk.reponse.ClientSecretResponse;
import lombok.*;
import java.time.LocalDateTime;
/**
* 生态市场,客户端端配置
* @TableName eco_market_client_secret
*/
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EcoMarketClientSecretModel {
/**
* 主键id
*/
private Long id;
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 客户端ID,分布式唯一UUID
*/
private String clientId;
/**
* 客户端密钥
*/
private String clientSecret;
/**
* 租户ID
*/
private Long tenantId;
/**
* 创建时间
*/
private LocalDateTime created;
/**
* 创建人id
*/
private Long creatorId;
/**
* 创建人
*/
private String creatorName;
/**
* 更新时间
*/
private LocalDateTime modified;
/**
* 转换为客户端密钥响应
*
* @return 客户端密钥响应
*/
public ClientSecretResponse toClientSecretResponse() {
return ClientSecretResponse.builder()
.id(id)
.name(name)
.description(description)
.clientId(clientId)
.clientSecret(clientSecret)
.tenantId(tenantId)
.created(created)
.build();
}
}

View File

@@ -0,0 +1,61 @@
package com.xspaceagi.eco.market.domain.model.valueobj;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 用于列表页,搜索本地数据库中的数据使用
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class QueryEcoMarketVo {
/**
* 名称,模糊查询
*/
private String name;
/**
* 细分类型,比如: 插件,智能体,工作流
* @see Published.TargetType
*/
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
private String targetSubType;
/**
* 市场类型,1:插件;2:模板;3:MCP
*/
private Integer dataType;
/**
* tab类型: 1: 全部; 2: 启用的;3:我的分享; 默认全部
*/
private Integer subTabType;
/**
* 分类编码
*/
private String categoryCode;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
private Integer shareStatus;
/**
* 使用状态,1:启用;2:禁用;
*/
private Integer useStatus;
/**
* 是否我的分享,0:否(生态市场获取的);1:是(我的分享)
*/
private Integer ownedFlag;
}

View File

@@ -0,0 +1,124 @@
package com.xspaceagi.eco.market.domain.repository;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.model.valueobj.QueryEcoMarketVo;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.infra.service.IQueryViewService;
import java.util.List;
public interface IEcoMarketClientConfigRepository extends IQueryViewService<EcoMarketClientConfigModel> {
/**
* 模板配置详情
*
* @param id 模板id
*/
EcoMarketClientConfigModel queryOneInfoById(Long id);
/**
* 批量根据kbIds查询知识库配置
*
* @param kbIds 知识库id列表
* @return 知识库配置列表
*/
List<EcoMarketClientConfigModel> queryListByIds(List<Long> kbIds);
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 更新
*
* @param model 模型
* @return id
*/
Long updateInfo(EcoMarketClientConfigModel model, UserContext userContext);
/**
* 根据uid更新
*
* @param model 模型
* @return id
*/
Long updateInfoByUid(EcoMarketClientConfigModel model, UserContext userContext);
/**
* 新增
*/
Long addInfo(EcoMarketClientConfigModel model, UserContext userContext);
/**
* 根据uid查询客户端配置
*
* @param uid 唯一ID
* @return 客户端配置
*/
EcoMarketClientConfigModel queryOneByUid(String uid);
/**
* 查询多个uid的客户端配置
*
* @param uids uid列表
* @return 客户端配置列表
*/
List<EcoMarketClientConfigModel> queryListByUids(List<String> uids);
/**
* 根据uid更新分享状态
*
* @param uid 唯一ID
* @param shareStatus 分享状态
* @param userContext 用户上下文
* @return 是否更新成功
*/
boolean updateShareStatusByUid(String uid, Integer shareStatus, String approveMessage, UserContext userContext);
/**
* 生态市场,用户分页查询结果
*
* @param queryEcoMarketVo 查询条件
* @param current 当前页
* @param size 每页大小
* @return 分页结果
*/
IPage<EcoMarketClientConfigModel> pageQuery(QueryEcoMarketVo queryEcoMarketVo, long current, long size);
/**
* 根据uid删除配置
*
* @param uid 配置唯一标识
*/
void deleteByUid(String uid);
/**
* 查询我的分享总数
*
* @return 总数
*/
Long queryTotalMyShare();
/**
* 检查配置是否重复
*
* @param targetId 目标id
* @param targetType 目标类型
* @param dataTypeEnum 数据类型
* @param uid 配置唯一标识(可选,用于排除自身)
* @return 是否重复
*/
boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum, String uid);
/**
* 查询我的分享和审核中的配置
*
* @return 配置列表
*/
List<EcoMarketClientConfigModel> queryMyShareAndReviewing();
}

View File

@@ -0,0 +1,94 @@
package com.xspaceagi.eco.market.domain.repository;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.domain.model.valueobj.QueryEcoMarketVo;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.system.spec.common.UserContext;
import java.util.List;
public interface IEcoMarketClientPublishConfigRepository {
/**
* 已发布配置详情
*
* @param id 配置id
*/
EcoMarketClientPublishConfigModel queryOneInfoById(Long id);
/**
* 根据uid查询已发布配置详情
*
* @param uid 配置唯一标识
* @return 已发布配置详情
*/
EcoMarketClientPublishConfigModel queryOneByUid(String uid);
/**
* 批量根据ids查询已发布配置
*
* @param ids id列表
* @return 已发布配置列表
*/
List<EcoMarketClientPublishConfigModel> queryListByIds(List<Long> ids);
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 根据uid删除
*
* @param uid uid
*/
void deleteByUid(String uid);
/**
* 更新
*
* @param model 模型
* @return id
*/
Long updateInfo(EcoMarketClientPublishConfigModel model, UserContext userContext);
/**
* 新增
*/
Long addInfo(EcoMarketClientPublishConfigModel model, UserContext userContext);
/**
* 生态市场,用户分页查询结果
*
* @param queryEcoMarketVo 查询条件
* @param current 当前页
* @param size 每页大小
* @return 分页结果
*/
IPage<EcoMarketClientPublishConfigModel> pageQuery(QueryEcoMarketVo queryEcoMarketVo, long current, long size);
/**
* 根据uids查询启用状态的配置
*
* @param uids 配置唯一标识列表
* @return 启用状态的配置列表
*/
List<EcoMarketClientPublishConfigModel> queryListByUids(List<String> uids);
/**
* 检查配置是否重复
*
* @param targetId 目标id
* @param targetType 目标类型
* @param dataTypeEnum 数据类型
* @return 是否重复
*/
boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum);
}

View File

@@ -0,0 +1,76 @@
package com.xspaceagi.eco.market.domain.repository;
import java.util.List;
import java.util.Map;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientSecretModel;
import com.xspaceagi.system.spec.common.UserContext;
public interface IEcoMarketClientSecretRepository {
/**
* 客户端密钥详情
*
* @param id 密钥id
*/
EcoMarketClientSecretModel queryOneInfoById(Long id);
/**
* 批量根据ids查询客户端密钥
*
* @param ids id列表
* @return 客户端密钥列表
*/
List<EcoMarketClientSecretModel> queryListByIds(List<Long> ids);
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 更新
*
* @param model 模型
* @return id
*/
Long updateInfo(EcoMarketClientSecretModel model, UserContext userContext);
/**
* 新增
*/
Long addInfo(EcoMarketClientSecretModel model, UserContext userContext);
/**
* 根据租户ID查询客户端密钥
*
* @param tenantId 租户ID
* @return 客户端密钥模型
*/
EcoMarketClientSecretModel queryByTenantId(Long tenantId);
/**
* 根据客户端ID查询客户端密钥
*
* @param clientId 客户端ID
* @return 客户端密钥模型
*/
EcoMarketClientSecretModel queryByClientId(String clientId);
/**
* 根据参数查询客户端密钥列表
*
* @param params 查询参数
* @return 客户端密钥列表
*/
List<EcoMarketClientSecretModel> queryListByParams(Map<String, Object> params);
/**
* 查询所有客户端密钥
*
* @return 客户端密钥列表
*/
List<EcoMarketClientSecretModel> queryAllList();
}

View File

@@ -0,0 +1,191 @@
package com.xspaceagi.eco.market.domain.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.model.valueobj.QueryEcoMarketVo;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.system.spec.common.UserContext;
import java.util.List;
import java.util.Map;
public interface IEcoMarketClientConfigDomainService {
/**
* 配置详情
*
* @param id 配置id
*/
EcoMarketClientConfigModel queryOneInfoById(Long id);
/**
* 批量根据ids查询配置
*
* @param ids id列表
* @return 配置列表
*/
List<EcoMarketClientConfigModel> queryListByIds(List<Long> ids);
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 更新
*
* @param model 模型
* @return id
*/
Long updateInfo(EcoMarketClientConfigModel model, UserContext userContext);
/**
* 根据uid更新
*
* @param model 模型
* @return id
*/
Long updateInfoByUid(EcoMarketClientConfigModel model, UserContext userContext);
/**
* 新增
*/
Long addInfo(EcoMarketClientConfigModel model, UserContext userContext);
/**
* 分页查询
*
* @param queryParams 查询参数
* @param current 当前页
* @param size 每页大小
* @return 分页结果
*/
IPage<EcoMarketClientConfigModel> pageQuery(Map<String, Object> queryParams, long current, long size);
/**
* 根据uid查询客户端配置
*
* @param uid 唯一ID
* @return 客户端配置
*/
EcoMarketClientConfigModel queryOneByUid(String uid);
/**
* 根据UID列表查询配置列表
*
* @param uids UID列表
* @return 配置列表
*/
List<EcoMarketClientConfigModel> queryListByUids(List<String> uids);
/**
* 下线配置
*
* @param uid 配置UID
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @param userContext 用户上下文
* @return 更新后的配置
*/
void offlineConfig(String uid, String clientId, String clientSecret, UserContext userContext);
/**
* 撤销发布
*
* @param uid 配置UID
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @param userContext 用户上下文
*/
void unpublishConfig(String uid, String clientId, String clientSecret, UserContext userContext);
/**
* 更新草稿配置
*
* @param model 配置模型
* @param userContext 用户上下文
* @return 配置ID
*/
Long updateDraft(EcoMarketClientConfigModel model, UserContext userContext);
/**
* 根据uid更新分享状态
*
* @param uid 配置唯一标识
* @param shareStatus 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回; @see
* EcoMarketShareStatusEnum
* @param approveMessage 审批消息
* @param userContext 用户上下文
* @return 是否更新成功
*/
boolean updateShareStatusByUid(String uid, Integer shareStatus, String approveMessage, UserContext userContext);
/**
* 根据目标id和目标类型获取配置json
*
* @param dataTypeEnum 数据类型
* @param targetId 目标id
* @param targetType 目标类型
* @param configParamJson 配置参数json
* @return 配置json
*
*/
String obtainConfigJson(EcoMarketDataTypeEnum dataTypeEnum, Long targetId, String targetType,
String configParamJson);
/**
* 分页查询启用状态的配置
*
* @param current 当前页
* @param size 每页大小
* @param dataType 市场类型,1:插件;2:模板;3:MCP
* @return 启用状态的配置分页结果
*/
IPage<EcoMarketClientConfigModel> pageQueryEnabled(QueryEcoMarketVo queryEcoMarketVo, long current, long size);
/**
* 分页查询我的分享
*
* @param queryEcoMarketVo 查询条件
* @param current 当前页
* @param size 每页大小
* @return 分页结果
*/
IPage<EcoMarketClientConfigModel> pageQueryMyShare(QueryEcoMarketVo queryEcoMarketVo, long current, long size);
/**
* 查询我的分享总数
*
* @return 总数
*/
Long queryTotalMyShare();
/**
* 根据uid删除配置
*
* @param uid 配置唯一标识
*/
void deleteByUid(String uid);
/**
* 检查配置是否重复
*
* @param targetId 目标id
* @param targetType 目标类型
* @param dataTypeEnum 数据类型
* @param uid 配置唯一标识(可选,用于排除自身)
* @return 是否重复
*/
boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum, String uid);
/**
* 查询我的分享和审核中的配置
*
* @return 配置列表
*/
List<EcoMarketClientConfigModel> queryMyShareAndReviewing();
}

View File

@@ -0,0 +1,121 @@
package com.xspaceagi.eco.market.domain.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xspaceagi.eco.market.domain.dto.req.UpdateAndEnableConfigReqDTO;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.domain.model.valueobj.QueryEcoMarketVo;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.system.spec.common.UserContext;
import java.util.List;
public interface IEcoMarketClientPublishConfigDomainService {
/**
* 已发布配置详情
*
* @param id 配置id
*/
EcoMarketClientPublishConfigModel queryOneInfoById(Long id);
/**
* 根据uid查询已发布配置详情
*
* @param uid 配置唯一标识
* @return 已发布配置详情
*/
EcoMarketClientPublishConfigModel queryOneByUid(String uid);
/**
* 批量根据ids查询已发布配置
*
* @param ids id列表
* @return 已发布配置列表
*/
List<EcoMarketClientPublishConfigModel> queryListByIds(List<Long> ids);
/**
* 更新
*
* @param model 模型
* @return id
*/
Long updateInfo(EcoMarketClientPublishConfigModel model, UserContext userContext);
/**
* 新增
*/
Long addInfo(EcoMarketClientPublishConfigModel model, UserContext userContext);
/**
* 保存或更新发布配置记录
* 如果存在相同UID的记录先删除再新增
*
* @param model 配置模型
* @param userContext 用户上下文
* @return 记录ID
*/
Long saveOrUpdateByUid(EcoMarketClientPublishConfigModel model, UserContext userContext);
/**
* 启用配置
*
* @param uid 配置唯一标识
* @param userContext 用户上下文
* @return 启用后的配置模型
*/
EcoMarketClientPublishConfigModel enableConfig(String uid, UserContext userContext);
/**
* 禁用配置
*
* @param uid 配置唯一标识
* @param userContext 用户上下文
* @return 禁用后的配置模型
*/
EcoMarketClientPublishConfigModel disableConfig(String uid, UserContext userContext);
/**
* 更新并启用配置
*
* @param request 更新配置参数
* @param userContext 用户上下文
* @return 启用后的配置模型
*/
EcoMarketClientPublishConfigModel updateAndEnableConfig(UpdateAndEnableConfigReqDTO request, UserContext userContext);
/**
* 分页查询启用状态的配置
*
* @param current 当前页
* @param size 每页大小
* @param queryEcoMarketVo 参数搜索配置
* @return 启用状态的配置分页结果
*/
IPage<EcoMarketClientPublishConfigModel> pageQueryEnabled(QueryEcoMarketVo queryEcoMarketVo, long current, long size);
/**
* 根据uids查询启用状态的配置
*
* @param uids 配置唯一标识列表
* @return 启用状态的配置列表
*/
List<EcoMarketClientPublishConfigModel> queryListByUids(List<String> uids);
/**
* 检查配置是否重复
*
* @param targetId 目标id
* @param targetType 目标类型
* @param dataTypeEnum 数据类型
* @return 是否重复
*/
boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum);
}

View File

@@ -0,0 +1,128 @@
package com.xspaceagi.eco.market.domain.service;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientSecretModel;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.system.spec.common.UserContext;
import java.util.List;
/**
* 生态市场客户端密钥服务接口
*/
public interface IEcoMarketClientSecretDomainService {
/**
* 查询客户端密钥详情
*
* @param id 配置id
* @return 客户端密钥模型
*/
EcoMarketClientSecretModel queryOneInfoById(Long id);
/**
* 批量根据ids查询客户端密钥
*
* @param ids id列表
* @return 客户端密钥列表
*/
List<EcoMarketClientSecretModel> queryListByIds(List<Long> ids);
/**
* 查询所有客户端密钥
*
* @return 客户端密钥列表
*/
List<EcoMarketClientSecretModel> queryAllList();
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 更新
*
* @param model 模型
* @param userContext 用户上下文
* @return id
*/
Long updateInfo(EcoMarketClientSecretModel model, UserContext userContext);
/**
* 新增
*
* @param model 模型
* @param userContext 用户上下文
* @return id
*/
Long addInfo(EcoMarketClientSecretModel model, UserContext userContext);
/**
* 从DTO保存客户端密钥
*
* @param clientSecretDTO 客户端密钥DTO
* @param userContext 用户上下文
* @return 保存后的id
*/
Long saveFromClientSecretDTO(ClientSecretDTO clientSecretDTO, UserContext userContext);
/**
* 根据租户ID查询客户端密钥
*
* @param tenantId 租户ID
* @return 客户端密钥模型
*/
EcoMarketClientSecretModel queryByTenantId(Long tenantId);
/**
* 根据客户端ID查询客户端密钥
*
* @param clientId 客户端ID
* @return 客户端密钥模型
*/
EcoMarketClientSecretModel queryByClientId(String clientId);
/**
* 检查租户是否已有客户端密钥
*
* @param tenantId 租户ID
* @return 是否存在
*/
boolean existsClientSecret(Long tenantId);
/**
* 获取或注册客户端密钥
*
* @param tenantId 租户ID
* @param name 名称,注册时必填
* @param description 描述,注册时必填
* @return 客户端密钥DTO
*/
ClientSecretDTO getOrRegisterClientSecret(Long tenantId, String name, String description);
/**
* 根据租户ID获取客户端密钥
*
* @param tenantId 租户ID
* @return 客户端密钥DTO
*/
ClientSecretDTO getByTenantId(Long tenantId);
/**
* 根据客户端ID获取客户端密钥
*
* @param clientId 客户端ID
* @return 客户端密钥DTO
*/
ClientSecretDTO getByClientId(String clientId);
/**
* 验证客户端密钥
*
* @param clientId 客户端ID
* @param clientSecret 客户端密钥
* @return 是否有效
*/
boolean validateClientSecret(String clientId, String clientSecret);
}

View File

@@ -0,0 +1,321 @@
package com.xspaceagi.eco.market.domain.service.impl;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xspaceagi.agent.core.sdk.enums.TargetTypeEnum;
import com.xspaceagi.eco.market.domain.adaptor.IEcoMarketAdaptor;
import com.xspaceagi.eco.market.domain.client.EcoMarketServerApiService;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.model.valueobj.QueryEcoMarketVo;
import com.xspaceagi.eco.market.domain.repository.IEcoMarketClientConfigRepository;
import com.xspaceagi.eco.market.domain.repository.IEcoMarketClientPublishConfigRepository;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientConfigDomainService;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketOwnedFlagEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketShareStatusEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketUseStatusEnum;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Slf4j
@Service
public class EcoMarketClientConfigDomainService implements IEcoMarketClientConfigDomainService {
@Resource
private IEcoMarketClientConfigRepository ecoMarketClientConfigRepository;
@Resource
private IEcoMarketClientPublishConfigRepository ecoMarketClientPublishConfigRepository;
@Resource
private EcoMarketServerApiService ecoMarketServerApiService;
@Resource
private IEcoMarketAdaptor ecoMarketAdaptor;
@Override
public EcoMarketClientConfigModel queryOneInfoById(Long id) {
return this.ecoMarketClientConfigRepository.queryOneInfoById(id);
}
@Override
public List<EcoMarketClientConfigModel> queryListByIds(List<Long> ids) {
return this.ecoMarketClientConfigRepository.queryListByIds(ids);
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public void deleteById(Long id) {
this.ecoMarketClientConfigRepository.deleteById(id);
}
@Override
public Long updateInfo(EcoMarketClientConfigModel model, UserContext userContext) {
return this.ecoMarketClientConfigRepository.updateInfo(model, userContext);
}
@Override
public Long updateInfoByUid(EcoMarketClientConfigModel model, UserContext userContext) {
return this.ecoMarketClientConfigRepository.updateInfoByUid(model, userContext);
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public Long addInfo(EcoMarketClientConfigModel model, UserContext userContext) {
return this.ecoMarketClientConfigRepository.addInfo(model, userContext);
}
@Override
public IPage<EcoMarketClientConfigModel> pageQuery(Map<String, Object> queryParams, long current, long size) {
// 查询总数
long total = this.ecoMarketClientConfigRepository.queryTotal(queryParams);
// 查询分页数据
List<OrderItem> orderItems = null; // 默认排序
long startIndex = (current - 1) * size;
List<EcoMarketClientConfigModel> records = this.ecoMarketClientConfigRepository
.pageQuery(queryParams, orderItems, startIndex, size);
// 构建分页结果
Page<EcoMarketClientConfigModel> page = new Page<>(current, size, total);
page.setRecords(records);
return page;
}
@Override
public EcoMarketClientConfigModel queryOneByUid(String uid) {
return this.ecoMarketClientConfigRepository.queryOneByUid(uid);
}
@Override
public List<EcoMarketClientConfigModel> queryListByUids(List<String> uids) {
log.info("Query client configs by uids: uids={}", uids);
if (CollectionUtils.isEmpty(uids)) {
return List.of();
}
return this.ecoMarketClientConfigRepository.queryListByUids(uids);
}
@Override
@DSTransactional(rollbackFor = Exception.class)
public void offlineConfig(String uid, String clientId, String clientSecret,
UserContext userContext) {
// 检查参数
if (uid == null || uid.isEmpty()) {
log.error("uid cannot be empty");
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置UID");
}
log.info("Offline client config: uid={}, clientId={}", uid, clientId);
// 查询配置详情
EcoMarketClientConfigModel configModel = queryOneByUid(uid);
if (configModel == null) {
log.error("Config not found, uid={}", uid);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
// 检查是否可以下线,只有已发布状态可以下线
if (!(Objects.equals(configModel.getShareStatus(), EcoMarketShareStatusEnum.PUBLISHED.getCode())
|| Objects.equals(configModel.getShareStatus(), EcoMarketShareStatusEnum.REVIEWING.getCode()))) {
log.error("Current state does not allow offline, uid={}", uid);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketOfflineOnlyPublishedOrReviewing);
}
// 调用服务器端下线接口
boolean offlineSuccess = ecoMarketServerApiService.offlineServerConfig(
uid, clientId, clientSecret);
if (!offlineSuccess) {
log.error("Offline server config failed");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketOfflineServerConfigFailed);
}
// 修改状态为已下线
configModel.setShareStatus(EcoMarketShareStatusEnum.OFFLINE.getCode()); // 已下线状态
configModel.setOfflineTime(LocalDateTime.now());
// 更新配置
this.ecoMarketClientConfigRepository.updateInfo(configModel, userContext);
}
@Override
public void unpublishConfig(String uid, String clientId, String clientSecret, UserContext userContext) {
// 检查参数
if (uid == null || uid.isEmpty()) {
log.error("uid cannot be empty");
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置UID");
}
log.info("Revoke publish client config: uid={}, clientId={}", uid, clientId);
// 查询配置详情
EcoMarketClientConfigModel configModel = queryOneByUid(uid);
if (configModel == null) {
log.error("Config not found, uid={}", uid);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
// 检查是否可以下线,只有已发布状态可以下线
if (!(Objects.equals(configModel.getShareStatus(), EcoMarketShareStatusEnum.REVIEWING.getCode()))) {
log.error("Current state does not allow revoke publish, uid={}", uid);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketRevokeOnlyReviewing);
}
// 调用服务器端下线接口
boolean unpublishSuccess = ecoMarketServerApiService.unpublishServerConfig(
uid, clientId, clientSecret);
if (!unpublishSuccess) {
log.error("Revoke publish server config failed");
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketOfflineServerConfigFailed);
}
// 查询生态市场的数据,如果有数据,则回滚状态为:已发布,否则回滚状态为:草稿
var ecoMarketData = ecoMarketServerApiService.getServerConfigDetail(uid, clientId, clientSecret);
if (ecoMarketData != null) {
configModel.setShareStatus(EcoMarketShareStatusEnum.PUBLISHED.getCode());
} else {
configModel.setShareStatus(EcoMarketShareStatusEnum.DRAFT.getCode());
}
// 更新配置
this.ecoMarketClientConfigRepository.updateInfo(configModel, userContext);
}
@Override
@DSTransactional(rollbackFor = Exception.class)
public Long updateDraft(EcoMarketClientConfigModel model, UserContext userContext) {
log.info("Update client config draft: uid={}, name={}", model.getUid(), model.getName());
// 检查参数
if (model == null || model.getId() == null) {
throw new IllegalArgumentException("Configuration model cannot be empty and ID must be specified");
}
// 确保状态为草稿
model.setShareStatus(EcoMarketShareStatusEnum.DRAFT.getCode());
// 设置修改时间
model.setModified(java.time.LocalDateTime.now());
// 更新配置
return this.ecoMarketClientConfigRepository.updateInfo(model, userContext);
}
@Override
@DSTransactional(rollbackFor = Exception.class)
public boolean updateShareStatusByUid(String uid, Integer shareStatus, String approveMessage,
UserContext userContext) {
log.info("Update client config share status: uid={}, shareStatus={}", uid, shareStatus);
// 参数校验
if (uid == null || uid.isEmpty()) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置UID");
}
if (shareStatus == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "分享状态");
}
// 检查配置是否存在
EcoMarketClientConfigModel existingConfig = this.ecoMarketClientConfigRepository.queryOneByUid(uid);
if (existingConfig == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketConfigInfoNotFound);
}
// 调用repository层更新分享状态
boolean result = this.ecoMarketClientConfigRepository.updateShareStatusByUid(uid, shareStatus, approveMessage,
userContext);
if (result) {
log.info("Share status update OK: uid={}, shareStatus={}", uid, shareStatus);
} else {
log.warn("Share status update failed: uid={}, shareStatus={}", uid, shareStatus);
}
return result;
}
@Override
public String obtainConfigJson(EcoMarketDataTypeEnum dataTypeEnum, Long targetId, String targetType,
String configParamJson) {
// check targetId and targetType
if (targetId == null || targetType == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "目标ID与目标类型");
}
switch (dataTypeEnum) {
case PLUGIN:
return this.ecoMarketAdaptor.queryPluginConfig(targetId, configParamJson);
case TEMPLATE:
return this.ecoMarketAdaptor.queryTemplateConfig(TargetTypeEnum.valueOf(targetType), targetId);
case MCP:
throw new UnsupportedOperationException("MCP数据类型不支持");
default:
throw new UnsupportedOperationException("不支持的数据类型");
}
}
@Override
public IPage<EcoMarketClientConfigModel> pageQueryEnabled(QueryEcoMarketVo queryEcoMarketVo, long current,
long size) {
log.info("Paged query enabled configs: current={}, size={}, dataType={}", current, size, queryEcoMarketVo.getDataType());
// 构建查询参数
queryEcoMarketVo.setUseStatus(EcoMarketUseStatusEnum.ENABLED.getCode());
queryEcoMarketVo.setOwnedFlag(EcoMarketOwnedFlagEnum.NO.getCode());
var page = this.ecoMarketClientConfigRepository.pageQuery(queryEcoMarketVo, current, size);
return page;
}
@Override
public IPage<EcoMarketClientConfigModel> pageQueryMyShare(QueryEcoMarketVo queryEcoMarketVo, long current,
long size) {
// 构建查询参数
queryEcoMarketVo.setOwnedFlag(EcoMarketOwnedFlagEnum.YES.getCode());
var page = this.ecoMarketClientConfigRepository.pageQuery(queryEcoMarketVo, current, size);
return page;
}
@Override
public void deleteByUid(String uid) {
this.ecoMarketClientConfigRepository.deleteByUid(uid);
}
@Override
public Long queryTotalMyShare() {
return this.ecoMarketClientConfigRepository.queryTotalMyShare();
}
@Override
public boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum, String uid) {
return this.ecoMarketClientConfigRepository.checkConfigRepeat(targetId, targetType, dataTypeEnum, uid);
}
@Override
public List<EcoMarketClientConfigModel> queryMyShareAndReviewing() {
return this.ecoMarketClientConfigRepository.queryMyShareAndReviewing();
}
}

View File

@@ -0,0 +1,763 @@
package com.xspaceagi.eco.market.domain.service.impl;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import com.xspaceagi.system.application.dto.UserDto;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xspaceagi.agent.core.adapter.application.AgentApplicationService;
import com.xspaceagi.agent.core.adapter.application.PublishApplicationService;
import com.xspaceagi.agent.core.adapter.dto.CategoryDto;
import com.xspaceagi.agent.core.adapter.dto.PublishApplyDto;
import com.xspaceagi.agent.core.adapter.dto.config.AgentConfigDto;
import com.xspaceagi.agent.core.adapter.repository.entity.Published;
import com.xspaceagi.agent.core.sdk.dto.PluginEnableOrUpdateDto;
import com.xspaceagi.agent.core.sdk.dto.TemplateEnableOrUpdateDto;
import com.xspaceagi.agent.core.sdk.enums.TargetTypeEnum;
import com.xspaceagi.agent.core.spec.utils.UrlFile;
import com.xspaceagi.custompage.application.service.ICustomPageBuildApplicationService;
import com.xspaceagi.custompage.application.service.ICustomPageConfigApplicationService;
import com.xspaceagi.custompage.domain.model.CustomPageConfigModel;
import com.xspaceagi.custompage.domain.proxypath.ICustomPageProxyPathService;
import com.xspaceagi.custompage.sdk.dto.ProjectType;
import com.xspaceagi.custompage.sdk.dto.PublishTypeEnum;
import com.xspaceagi.eco.market.domain.adaptor.IEcoMarketAdaptor;
import com.xspaceagi.eco.market.domain.assembler.EcoMarketConfigTranslator;
import com.xspaceagi.eco.market.domain.client.EcoMarketServerApiService;
import com.xspaceagi.eco.market.domain.dto.req.UpdateAndEnableConfigReqDTO;
import com.xspaceagi.eco.market.domain.dto.resp.ServerConfigDetailRespDTO;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.domain.model.valueobj.QueryEcoMarketVo;
import com.xspaceagi.eco.market.domain.repository.IEcoMarketClientPublishConfigRepository;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientConfigDomainService;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientPublishConfigDomainService;
import com.xspaceagi.eco.market.domain.specification.EcoMarkerSecretWrapper;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketOwnedFlagEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketUseStatusEnum;
import com.xspaceagi.mcp.sdk.dto.CreatorDto;
import com.xspaceagi.mcp.sdk.dto.McpDto;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.enums.YesOrNoEnum;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import com.xspaceagi.system.spec.utils.IPUtil;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class EcoMarketClientPublishConfigDomainService implements IEcoMarketClientPublishConfigDomainService {
@Resource
private IEcoMarketClientPublishConfigRepository ecoMarketClientPublishConfigRepository;
@Resource
private IEcoMarketAdaptor ecoMarketAdaptor;
@Resource
private IEcoMarketClientConfigDomainService ecoMarketClientConfigDomainService;
@Resource
private EcoMarketServerApiService ecoMarketServerApiService;
@Resource
private EcoMarketConfigTranslator ecoMarketConfigTranslator;
@Resource
private EcoMarkerSecretWrapper ecoMarkerSecretWrapper;
@Resource
private ICustomPageConfigApplicationService customPageConfigApplicationService;
@Resource
private ICustomPageBuildApplicationService customPageBuildApplicationService;
@Resource
private ICustomPageProxyPathService customPageProxyPathService;
@Resource
private PublishApplicationService publishApplicationService;
@Resource
private AgentApplicationService agentApplicationService;
@Override
public EcoMarketClientPublishConfigModel queryOneInfoById(Long id) {
return this.ecoMarketClientPublishConfigRepository.queryOneInfoById(id);
}
@Override
public List<EcoMarketClientPublishConfigModel> queryListByIds(List<Long> ids) {
return this.ecoMarketClientPublishConfigRepository.queryListByIds(ids);
}
@Override
public Long updateInfo(EcoMarketClientPublishConfigModel model, UserContext userContext) {
return this.ecoMarketClientPublishConfigRepository.updateInfo(model, userContext);
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public Long addInfo(EcoMarketClientPublishConfigModel model, UserContext userContext) {
return this.ecoMarketClientPublishConfigRepository.addInfo(model, userContext);
}
@Override
public EcoMarketClientPublishConfigModel queryOneByUid(String uid) {
return this.ecoMarketClientPublishConfigRepository.queryOneByUid(uid);
}
/**
* 保存或更新发布配置记录
* 如果存在相同UID的记录先删除再新增
*
* @param model 配置模型
* @param userContext 用户上下文
* @return 记录ID
*/
@DSTransactional(rollbackFor = Exception.class)
@Override
public Long saveOrUpdateByUid(EcoMarketClientPublishConfigModel model, UserContext userContext) {
if (model == null || model.getUid() == null) {
log.error("Save publish config param error: model={}", model);
throw new IllegalArgumentException("Configuration model or UID cannot be empty");
}
String uid = model.getUid();
log.info("Save or update publish config: uid={}", uid);
var existObj = this.ecoMarketClientPublishConfigRepository.queryOneByUid(uid);
if (existObj != null) {
// 先删除已有记录(如果存在)
this.ecoMarketClientPublishConfigRepository.deleteByUid(uid);
model.setCreated(existObj.getCreated());
}
// 添加新记录
return this.ecoMarketClientPublishConfigRepository.addInfo(model, userContext);
}
/**
* 启用配置
*
* @param uid 配置唯一标识
* @param userContext 用户上下文
* @return 启用后的配置模型
*/
@DSTransactional(rollbackFor = Exception.class)
@Override
public EcoMarketClientPublishConfigModel enableConfig(String uid, UserContext userContext) {
log.info("Enable config: uid={}", uid);
// 直接查询本地配置
EcoMarketClientPublishConfigModel config = this.ecoMarketClientPublishConfigRepository.queryOneByUid(uid);
// 如果本地没有记录,抛出异常
if (config == null) {
log.info("No published config locally, uid={}", uid);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
// 更新状态为启用
config.setUseStatus(EcoMarketUseStatusEnum.ENABLED.getCode());
// 调用启用接口
Long targetId = enableTargetByType(config, userContext);
// 更新targetId用于后续禁用使用
if (targetId != null) {
config.setTargetId(targetId);
}
// 更新发布配置记录
this.ecoMarketClientPublishConfigRepository.updateInfo(config, userContext);
// 更新本地配置记录
EcoMarketClientConfigModel existLocalConfig = this.ecoMarketClientConfigDomainService.queryOneByUid(uid);
if (existLocalConfig != null) {
existLocalConfig.setUseStatus(EcoMarketUseStatusEnum.ENABLED.getCode());
this.ecoMarketClientConfigDomainService.updateInfo(existLocalConfig, userContext);
} else {
log.warn("No local config, uid={}, creating local config", uid);
// 根据 publish 转换本地配置
EcoMarketClientConfigModel localConfig = EcoMarketClientPublishConfigModel
.toClientConfigModel(config);
localConfig.setId(null);
// 保存本地配置记录
this.ecoMarketClientConfigDomainService.addInfo(localConfig, userContext);
}
// 返回更新后的配置
return this.ecoMarketClientPublishConfigRepository.queryOneByUid(uid);
}
/**
* 更新并启用配置
*
* @param request 请求参数
* @param userContext 用户上下文
* @return 启用后的配置模型
*/
@DSTransactional(rollbackFor = Throwable.class)
@Override
public EcoMarketClientPublishConfigModel updateAndEnableConfig(UpdateAndEnableConfigReqDTO request,
UserContext userContext) {
var uid = request.getUid();
var configParamJson = request.getConfigParamJson();
var configJson = request.getConfigJson();
log.info("Update and enable config: uid={}", uid);
// 获取客户端密钥
Long tenantId = userContext.getTenantId();
ClientSecretDTO clientSecret = this.ecoMarkerSecretWrapper.obtainClientSecretOrRegister(tenantId);
if (clientSecret == null) {
log.error("Get client secret failed: uid={}", uid);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketClientSecretFetchFailed);
}
// 从远程服务器获取最新配置数据
ServerConfigDetailRespDTO serverConfig;
try {
serverConfig = ecoMarketServerApiService.getServerConfigDetail(
uid,
clientSecret.getClientId(),
clientSecret.getClientSecret());
log.info("Server config detail OK: uid={}", uid);
} catch (Exception e) {
log.error("Server config detail failed: uid={}, error={}", uid, e.getMessage(), e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketUnsupportedDataType,
"从服务器获取配置详情失败: " + e.getMessage());
}
// 如果服务器返回为空,抛出异常
if (serverConfig == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "服务器未找到配置记录");
}
// 删除本地的配置,然后重新创建
Long oldTargetId = null;
var existPublishObj = this.ecoMarketClientPublishConfigRepository.queryOneByUid(uid);
if (existPublishObj != null) {
oldTargetId = existPublishObj.getTargetId();
this.ecoMarketClientPublishConfigRepository.deleteByUid(uid);
}
var existLocalObj = this.ecoMarketClientConfigDomainService.queryOneByUid(uid);
// 转换服务器配置为客户端配置, 设置租户ID为空,避免后续使用
EcoMarketClientConfigModel clientConfig = ecoMarketConfigTranslator.translateServerConfigToClientConfig(
serverConfig, null);
// 检查转换结果
if (clientConfig == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound, "配置转换失败");
}
// 将客户端配置转换为发布配置
EcoMarketClientPublishConfigModel publishConfig = ecoMarketConfigTranslator
.translateClientConfigToPublishConfig(clientConfig);
// 设置旧的targetId,如果没有,会按照新插件/模板,本地创建;如果有值,启用会更新插件配置
publishConfig.setTargetId(oldTargetId);
// 设置状态为启用
publishConfig.setUseStatus(EcoMarketUseStatusEnum.DISABLED.getCode());
publishConfig.setCreateClientId(clientSecret.getClientId());
// 设置前端给的参数配置json
publishConfig.setConfigParamJson(configParamJson);
if (StringUtils.isNoneBlank(configJson)) {
publishConfig.setConfigJson(configJson);
}
// 确保用户的我的分享,标记不丢失,需要用老数据更新下
if (existLocalObj != null) {
this.ecoMarketClientConfigDomainService.deleteByUid(uid);
// 打上我的分享标记
publishConfig.setOwnedFlag(existLocalObj.getOwnedFlag());
// 启用/禁用标记
publishConfig.setCreatorId(existLocalObj.getCreatorId());
publishConfig.setCreatorName(existLocalObj.getCreatorName());
}
// 保存发布配置
this.ecoMarketClientPublishConfigRepository.addInfo(publishConfig, userContext);
// 重新查询
publishConfig = this.ecoMarketClientPublishConfigRepository.queryOneByUid(uid);
// 调用启用接口
try {
Long targetId = enableTargetByType(publishConfig, userContext);
// 更新targetId用于后续禁用使用
if (targetId != null) {
// 更新targetId
publishConfig.setTargetId(targetId);
publishConfig.setUseStatus(EcoMarketUseStatusEnum.ENABLED.getCode());
// 更新配置记录
this.ecoMarketClientPublishConfigRepository.updateInfo(publishConfig, userContext);
// 根据 publish 转换本地配置
EcoMarketClientConfigModel localConfig = EcoMarketClientPublishConfigModel
.toClientConfigModel(publishConfig);
localConfig.setId(null);
// 保存本地配置记录
this.ecoMarketClientConfigDomainService.addInfo(localConfig, userContext);
} else {
log.warn("Enable config failed: uid={}, targetId empty from create response", uid);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketEnableConfigFailed, "targetId empty from create response");
}
} catch (Exception e) {
log.error("Enable config failed: uid={}", uid, e);
throw e;
}
// 返回更新后的配置
return this.ecoMarketClientPublishConfigRepository.queryOneByUid(uid);
}
/**
* 禁用配置
*
* @param uid 配置唯一标识
* @param userContext 用户上下文
* @return 禁用后的配置模型
*/
@DSTransactional(rollbackFor = Exception.class)
@Override
public EcoMarketClientPublishConfigModel disableConfig(String uid, UserContext userContext) {
log.info("Disable config: uid={}", uid);
// 查询本地配置
EcoMarketClientPublishConfigModel config = this.ecoMarketClientPublishConfigRepository.queryOneByUid(uid);
// 如果本地没有记录,抛出异常
if (config == null) {
log.error("Config to disable not found: uid={}", uid);
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
// 设置状态为禁用
config.setUseStatus(EcoMarketUseStatusEnum.DISABLED.getCode());
try {
// 调用禁用接口
disableTargetByType(config);
} catch (Exception e) {
log.error("Disable API call failed: uid={}, error={}", uid, e.getMessage(), e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketUnsupportedDataType, "禁用接口调用失败: " + e.getMessage());
}
// 更新配置记录
this.ecoMarketClientPublishConfigRepository.updateInfo(config, userContext);
EcoMarketClientConfigModel clientConfig = this.ecoMarketClientConfigDomainService.queryOneByUid(uid);
if (clientConfig != null) {
// 更新本地配置
clientConfig.setUseStatus(EcoMarketUseStatusEnum.DISABLED.getCode());
this.ecoMarketClientConfigDomainService.updateInfo(clientConfig, userContext);
}
// 返回更新后的配置
return this.ecoMarketClientPublishConfigRepository.queryOneByUid(uid);
}
/**
* 根据配置类型启用目标
*
* @param config 配置模型
* @return 目标ID
*/
private Long enableTargetByType(EcoMarketClientPublishConfigModel config, UserContext userContext) {
if (config == null) {
throw new IllegalArgumentException("Configuration model cannot be empty");
}
// 判断数据类型
Integer dataType = config.getDataType();
EcoMarketDataTypeEnum dataTypeEnum = EcoMarketDataTypeEnum.getByCode(dataType);
if (dataTypeEnum == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishedConfigNotFound, "无效的数据类型: " + dataType);
}
// 根据数据类型调用不同的启用接口
Long resultId;
try {
switch (dataTypeEnum) {
case PLUGIN -> {
// 启用插件
PluginEnableOrUpdateDto pluginDto = new PluginEnableOrUpdateDto();
pluginDto.setPluginId(config.getTargetId());
pluginDto.setUserId(userContext.getUserId());
pluginDto.setConfig(config.getConfigJson());
pluginDto.setCategory(config.getCategoryCode());
// 设置配置参数
pluginDto.setParamJson(config.getConfigParamJson());
pluginDto.setIcon(config.getIcon());
pluginDto.setName(config.getName());
// check configJson 不能为空
if (pluginDto.getConfig() == null) {
log.warn("Config JSON cannot be empty: uid={}", config.getUid());
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置JSON");
}
resultId = ecoMarketAdaptor.pluginEnableOrUpdate(pluginDto);
}
case TEMPLATE -> {
// 启用模板(智能体、工作流)
TargetTypeEnum targetType = TargetTypeEnum.valueOf(config.getTargetType());
boolean isPageApp = targetType == TargetTypeEnum.Agent && Published.TargetSubType.PageApp.name().equals(config.getTargetSubType());
if (!isPageApp) {
TemplateEnableOrUpdateDto templateDto = new TemplateEnableOrUpdateDto();
templateDto.setTargetId(config.getTargetId());
templateDto.setTargetType(targetType);
templateDto.setUserId(userContext.getUserId());
templateDto.setConfig(config.getConfigJson());
templateDto.setCategory(config.getCategoryCode());
templateDto.setIcon(config.getIcon());
templateDto.setName(config.getName());
// 转换目标类型
try {
templateDto.setTargetType(TargetTypeEnum.valueOf(config.getTargetType()));
} catch (IllegalArgumentException e) {
log.error("Invalid target type: uid={}, targetType={}", config.getUid(), config.getTargetType(), e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishedConfigNotFound,
"无效的目标类型: " + config.getTargetType());
}
// check configJson 不能为空
if (templateDto.getConfig() == null) {
log.warn("Config JSON cannot be empty: uid={}", config.getUid());
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置JSON");
}
resultId = ecoMarketAdaptor.templateEnableOrUpdate(templateDto);
} else {
//应用页面
String pageZipUrl = config.getPageZipUrl();
if (StringUtils.isBlank(pageZipUrl)) {
log.warn("Page zip URL required: uid={}", config.getUid());
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "页面压缩包URL");
}
try {
// 下载页面压缩包
log.info("Downloading page zip: uid={}, url={}", config.getUid(), pageZipUrl);
byte[] zipBytes = UrlFile.downLoad(pageZipUrl);
if (zipBytes == null || zipBytes.length == 0) {
log.error("Page zip download failed or empty: uid={}", config.getUid());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageArchiveDownloadFailed);
}
// 创建页面项目
log.info("Creating page project: uid={}, spaceId={}, name={}", config.getUid(), -1L, config.getName());
CustomPageConfigModel pageModel = new CustomPageConfigModel();
pageModel.setName(config.getName());
pageModel.setDescription(config.getDescription());
pageModel.setSpaceId(-1L);
pageModel.setIcon(config.getIcon());
pageModel.setNeedLogin(YesOrNoEnum.Y.getKey()); // 需要登录
pageModel.setProjectType(ProjectType.ONLINE_DEPLOY);
com.xspaceagi.system.spec.dto.ReqResult<CustomPageConfigModel> createResult = customPageConfigApplicationService.create(pageModel, userContext);
if (!createResult.isSuccess()) {
log.error("Create page project failed: uid={}, error={}", config.getUid(), createResult.getMessage());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageProjectCreateFailed);
}
CustomPageConfigModel createdPageModel = createResult.getData();
Long projectId = createdPageModel.getId();
log.info("Create page project OK: uid={}, projectId={}", config.getUid(), projectId);
// 上传压缩包
log.info("Uploading page zip: uid={}, projectId={}", config.getUid(), projectId);
MultipartFile multipartFile = new ByteArrayMultipartFile(zipBytes, "project_" + projectId + ".zip", "application/zip");
try {
com.xspaceagi.system.spec.dto.ReqResult<Map<String, Object>> uploadResult = customPageConfigApplicationService.uploadProject(
createdPageModel, multipartFile, true, userContext);
if (!uploadResult.isSuccess()) {
log.error("Page zip upload failed: uid={}, projectId={}, error={}", config.getUid(), projectId, uploadResult.getMessage());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageArchiveUploadFailed);
}
log.info("Page zip upload OK: uid={}, projectId={}", config.getUid(), projectId);
} catch (Exception e) {
log.error("Page zip upload failed: uid={}, projectId={}", config.getUid(), projectId, e);
try {
customPageConfigApplicationService.deleteProject(projectId, userContext);
} catch (Exception e1) {
log.error("Cleanup page project failed: uid={}, projectId={}", config.getUid(), projectId, e1);
}
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPageArchiveUploadFailed);
}
// 发布页面
log.info("Publishing page: uid={}, projectId={}", config.getUid(), projectId);
com.xspaceagi.system.spec.dto.ReqResult<java.util.Map<String, Object>> buildResult = customPageBuildApplicationService.build(
projectId, PublishTypeEnum.AGENT.name(), userContext);
if (!buildResult.isSuccess()) {
log.error("Publish page failed: uid={}, projectId={}, error={}", config.getUid(), projectId, buildResult.getMessage());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPagePublishFailed);
}
log.info("Publish page OK: uid={}, projectId={}", config.getUid(), projectId);
Long agentId = createdPageModel.getDevAgentId();
// 获取智能体配置作为 targetConfig
AgentConfigDto agentConfigDto = agentApplicationService.queryById(agentId);
if (agentConfigDto == null) {
log.error("Get agent config failed: uid={}, agentId={}", config.getUid(), agentId);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketAppPageEnableFailed);
}
UserDto userDto = new UserDto();
userDto.setId(userContext.getUserId());
userDto.setUserName(userContext.getUserName());
userDto.setNickName(userContext.getNickName());
//发布智能体
PublishApplyDto publishApply = new PublishApplyDto();
publishApply.setSpaceId(-1L);
publishApply.setTargetId(agentId);
publishApply.setTargetType(Published.TargetType.Agent);
publishApply.setTargetSubType(Published.TargetSubType.PageApp);
publishApply.setApplyUser(userDto);
publishApply.setName(config.getName());
publishApply.setDescription(config.getDescription());
publishApply.setIcon(generateIcon(config.getIcon()));
publishApply.setChannels(List.of(Published.PublishChannel.System));
publishApply.setScope(Published.PublishScope.Tenant);
publishApply.setCategory(CategoryDto.PluginCategoryEnum.Other.getName());
publishApply.setTargetConfig(agentConfigDto);
publishApply.setAllowCopy(YesOrNoEnum.Y.getKey());
publishApply.setOnlyTemplate(YesOrNoEnum.Y.getKey());
Long applyId = publishApplicationService.publishApply(publishApply);
publishApplicationService.publish(applyId);
// 获取生产环境地址
String prodProxyPath = customPageProxyPathService.getProdProxyPath(projectId);
log.info("Prod URL OK: uid={}, projectId={}, prodProxyPath={}", config.getUid(), projectId, prodProxyPath);
resultId = agentId;
} catch (EcoMarketException e) {
throw e;
} catch (Exception e) {
log.error("Handle page project failed: uid={}", config.getUid(), e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketAppPageEnableFailed);
}
}
}
case MCP -> {
// MCP类型启用
var configJson = config.getConfigJson();
if (StringUtils.isBlank(configJson)) {
log.error("MCP config content required: uid={}", config.getUid());
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "MCP配置");
}
McpDto mcpDtoFromJson = JSONObject.parseObject(configJson, McpDto.class);
if (mcpDtoFromJson == null) {
log.error("MCP config parse failed: uid={}", config.getUid());
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketMcpConfigParseFailed);
}
mcpDtoFromJson.setId(null);
mcpDtoFromJson.setSpaceId(null);
mcpDtoFromJson.setUid(config.getUid());
mcpDtoFromJson.setDescription(config.getDescription());
mcpDtoFromJson.setCategory(config.getCategoryCode());
mcpDtoFromJson.setIcon(config.getIcon());
mcpDtoFromJson.setName(config.getName());
mcpDtoFromJson.setCreatorId(userContext.getUserId());
mcpDtoFromJson.setCreated(null);
mcpDtoFromJson.setModified(null);
var creator = CreatorDto.builder()
.userId(userContext.getUserId())
.userName(userContext.getUserName())
.nickName(userContext.getNickName())
.avatar(userContext.getAvatar())
.build();
mcpDtoFromJson.setCreator(creator);
resultId = ecoMarketAdaptor.deployOfficialMcp(mcpDtoFromJson);
}
default -> {
log.error("Unsupported data type: {}", dataType);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishedConfigNotFound, "不支持的数据类型");
}
}
log.info("Enable API OK: uid={}, resultId={}", config.getUid(), resultId);
return resultId;
} catch (EcoMarketException e) {
// 业务异常直接抛出
throw e;
} catch (Exception e) {
log.error("Enable config failed: uid={}", config.getUid(), e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketEnableConfigFailed);
}
}
private String generateIcon(String iconUrl) {
// 检查pluginAddDto.getIcon()是否可网络上访问
try {
if (StringUtils.isNotBlank(iconUrl)) {
//检查是否为内网URL
if (!IPUtil.isInternalAddress(iconUrl)) {
return iconUrl;
}
}
} catch (Exception e) {
// 忽略
log.warn("Plugin icon download failed {}", iconUrl);
}
return null;
}
/**
* 根据配置类型禁用目标
*
* @param config 配置模型
*/
private void disableTargetByType(EcoMarketClientPublishConfigModel config) {
if (config == null) {
throw new IllegalArgumentException("Configuration model cannot be empty");
}
// 判断数据类型
Integer dataType = config.getDataType();
EcoMarketDataTypeEnum dataTypeEnum = EcoMarketDataTypeEnum.getByCode(dataType);
if (dataTypeEnum == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishedConfigNotFound, "无效的数据类型: " + dataType);
}
// 检查targetId是否存在
if (config.getTargetId() == null) {
log.warn("Disable config: targetId empty, uid={}", config.getUid());
return; // 没有targetId无法禁用但不抛异常
}
try {
switch (dataTypeEnum) {
case PLUGIN -> {
// 禁用插件
ecoMarketAdaptor.disablePlugin(config.getTargetId());
}
case TEMPLATE -> {
// 禁用模板(智能体、工作流)
TargetTypeEnum targetType = TargetTypeEnum.valueOf(config.getTargetType());
ecoMarketAdaptor.disableTemplate(targetType, config.getTargetId());
}
case MCP -> {
// 停止MCP
ecoMarketAdaptor.stopOfficialMcp(config.getTargetId());
}
default -> {
log.error("Unsupported data type: {}", dataType);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketPublishedConfigNotFound, "不支持的数据类型");
}
}
log.info("Disable API OK: uid={}, targetId={}", config.getUid(), config.getTargetId());
} catch (Exception e) {
log.error("Disable config failed: uid={},", config.getUid(), e);
throw EcoMarketException.build(BizExceptionCodeEnum.ecoMarketDisableConfigFailed);
}
}
@Override
public IPage<EcoMarketClientPublishConfigModel> pageQueryEnabled(QueryEcoMarketVo queryEcoMarketVo, long current,
long size) {
// 只查询启用状态的配置
queryEcoMarketVo.setUseStatus(EcoMarketUseStatusEnum.ENABLED.getCode());
queryEcoMarketVo.setOwnedFlag(EcoMarketOwnedFlagEnum.NO.getCode());
return this.ecoMarketClientPublishConfigRepository.pageQuery(queryEcoMarketVo, current, size);
}
@Override
public List<EcoMarketClientPublishConfigModel> queryListByUids(List<String> uids) {
if (uids == null || uids.isEmpty()) {
return List.of();
}
return this.ecoMarketClientPublishConfigRepository.queryListByUids(uids);
}
@Override
public boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum) {
return this.ecoMarketClientPublishConfigRepository.checkConfigRepeat(targetId, targetType, dataTypeEnum);
}
/**
* 字节数组 MultipartFile 实现类
*/
@Data
@AllArgsConstructor
private static class ByteArrayMultipartFile implements MultipartFile {
private final byte[] content;
private final String name;
private final String contentType;
@Override
public String getOriginalFilename() {
return name;
}
@Override
public boolean isEmpty() {
return content == null || content.length == 0;
}
@Override
public long getSize() {
return content != null ? content.length : 0;
}
@Override
public byte[] getBytes() throws IOException {
return content;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(content);
}
@Override
public org.springframework.core.io.Resource getResource() {
return new ByteArrayResource(content) {
@Override
public String getFilename() {
return name;
}
};
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
java.nio.file.Files.write(dest.toPath(), content);
}
}
}

View File

@@ -0,0 +1,233 @@
package com.xspaceagi.eco.market.domain.service.impl;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.google.common.eventbus.EventBus;
import com.xspaceagi.eco.market.domain.client.EcoMarketServerApiService;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientSecretModel;
import com.xspaceagi.eco.market.domain.repository.IEcoMarketClientSecretRepository;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientSecretDomainService;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.eco.market.spec.util.EcoMarketCaffeineCacheUtil;
import com.xspaceagi.pay.spec.gateway.PayGatewayOutboundCacheEvictSupport;
import com.xspaceagi.pay.spec.gateway.PayGatewayOutboundCacheEvictor;
import com.xspaceagi.system.spec.common.RequestContext;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.event.PullMessageEvent;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
@Slf4j
@Service
public class EcoMarketClientSecretDomainService implements IEcoMarketClientSecretDomainService {
@Resource
private IEcoMarketClientSecretRepository ecoMarketClientSecretRepository;
@Resource
private EcoMarketServerApiService ecoMarketServerApiService;
@Resource
private EventBus eventBus;
@Autowired(required = false)
private PayGatewayOutboundCacheEvictor payGatewayOutboundCacheEvictor;
@Override
public EcoMarketClientSecretModel queryOneInfoById(Long id) {
return this.ecoMarketClientSecretRepository.queryOneInfoById(id);
}
@Override
public List<EcoMarketClientSecretModel> queryListByIds(List<Long> ids) {
return this.ecoMarketClientSecretRepository.queryListByIds(ids);
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public void deleteById(Long id) {
EcoMarketClientSecretModel existing = queryOneInfoById(id);
this.ecoMarketClientSecretRepository.deleteById(id);
if (existing != null) {
evictPayGatewayOutboundCache(existing.getTenantId());
}
}
@Override
public Long updateInfo(EcoMarketClientSecretModel model, UserContext userContext) {
Long id = this.ecoMarketClientSecretRepository.updateInfo(model, userContext);
evictPayGatewayOutboundCache(model.getTenantId());
return id;
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public Long addInfo(EcoMarketClientSecretModel model, UserContext userContext) {
Long id = this.ecoMarketClientSecretRepository.addInfo(model, userContext);
evictPayGatewayOutboundCache(model.getTenantId());
return id;
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public Long saveFromClientSecretDTO(ClientSecretDTO clientSecretDTO, UserContext userContext) {
if (clientSecretDTO == null) {
return null;
}
log.info("Save client secret, tenantId: {}, clientId: {}", clientSecretDTO.getTenantId(), clientSecretDTO.getClientId());
// 先查询是否已存在该租户的密钥
EcoMarketClientSecretModel existingModel = queryByTenantId(clientSecretDTO.getTenantId());
// 构建模型对象
EcoMarketClientSecretModel model = EcoMarketClientSecretModel.builder()
.name(clientSecretDTO.getName())
.description(clientSecretDTO.getDescription())
.clientId(clientSecretDTO.getClientId())
.clientSecret(clientSecretDTO.getClientSecret())
.tenantId(clientSecretDTO.getTenantId())
.build();
Long id;
if (existingModel != null) {
// 已存在,则更新
model.setId(existingModel.getId());
id = updateInfo(model, userContext);
log.info("Client secret updated, id: {}", id);
} else {
// 不存在,则新增
id = addInfo(model, userContext);
log.info("Client secret created, id: {}", id);
}
return id;
}
private void evictPayGatewayOutboundCache(Long tenantId) {
PayGatewayOutboundCacheEvictSupport.evictIfPresent(payGatewayOutboundCacheEvictor, tenantId);
}
@Override
public EcoMarketClientSecretModel queryByTenantId(Long tenantId) {
if (tenantId == null) {
return null;
}
// 通过仓库层查询
return this.ecoMarketClientSecretRepository.queryByTenantId(tenantId);
}
@Override
public EcoMarketClientSecretModel queryByClientId(String clientId) {
if (clientId == null) {
return null;
}
// 通过仓库层查询
return this.ecoMarketClientSecretRepository.queryByClientId(clientId);
}
@Override
public boolean existsClientSecret(Long tenantId) {
return queryByTenantId(tenantId) != null;
}
@Override
public ClientSecretDTO getOrRegisterClientSecret(Long tenantId, String name, String description) {
if (Objects.isNull(tenantId)) {
log.error("Tenant ID cannot be empty");
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "租户ID");
}
// 先查询是否存在
EcoMarketClientSecretModel model = queryByTenantId(tenantId);
if (model != null) {
return getByTenantId(tenantId);
}
// 不存在调用服务器端API注册
log.info("Client secret missing, registering on server: tenantId={}, name={}", tenantId, name);
// 调用服务器API注册客户端
// 主动生成租户的clientId, 并保存到内存中, 用于后续的注册.注:
// 服务器不一定认客户端给的clientId,正常情况会使用客户端给的clientId, 如果客户端给的clientId不合法,
// 则使用生成的clientId返回
String clientId = EcoMarketCaffeineCacheUtil.getTenantClientIdWithCache(tenantId);
ClientSecretDTO clientSecretDTO = ecoMarketServerApiService.registerClient(name, description, tenantId,
clientId);
// 保存到本地
UserContext userContext = UserContext.builder()
.tenantId(tenantId)
.userId(0L)
.userName("system")
.build();
saveFromClientSecretDTO(clientSecretDTO, userContext);
// 注册成功后, 触发EventBus事件异步拉取消息
var pullMessageEvent = PullMessageEvent.builder()
.userId(0L)
.tenantId(RequestContext.get().getTenantId())
.clientId(clientId)
.build();
eventBus.post(pullMessageEvent);
return clientSecretDTO;
}
@Override
public ClientSecretDTO getByTenantId(Long tenantId) {
EcoMarketClientSecretModel model = queryByTenantId(tenantId);
if (model == null) {
return null;
}
return ClientSecretDTO.builder()
.id(model.getId())
.name(model.getName())
.description(model.getDescription())
.clientId(model.getClientId())
.clientSecret(model.getClientSecret())
.tenantId(model.getTenantId())
.build();
}
@Override
public ClientSecretDTO getByClientId(String clientId) {
EcoMarketClientSecretModel model = queryByClientId(clientId);
if (model == null) {
return null;
}
return ClientSecretDTO.builder()
.id(model.getId())
.name(model.getName())
.description(model.getDescription())
.clientId(model.getClientId())
.clientSecret(model.getClientSecret())
.tenantId(model.getTenantId())
.build();
}
@Override
public boolean validateClientSecret(String clientId, String clientSecret) {
EcoMarketClientSecretModel model = queryByClientId(clientId);
if (model == null || clientSecret == null) {
return false;
}
return clientSecret.equals(model.getClientSecret());
}
@Override
public List<EcoMarketClientSecretModel> queryAllList() {
return this.ecoMarketClientSecretRepository.queryAllList();
}
}

View File

@@ -0,0 +1,77 @@
package com.xspaceagi.eco.market.domain.specification;
import com.xspaceagi.eco.market.domain.service.IEcoMarketClientSecretDomainService;
import com.xspaceagi.eco.market.sdk.model.ClientSecretDTO;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Slf4j
@Service
public class EcoMarkerSecretWrapper {
@Resource
@Lazy
private IEcoMarketClientSecretDomainService ecoMarketClientSecretDomainService;
/**
* 获取客户端密钥
*
* @return 客户端密钥DTO
*/
public ClientSecretDTO obtainClientSecretOrRegister(Long tenantId) {
if (Objects.isNull(tenantId)) {
log.error("Tenant ID cannot be empty");
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "租户ID");
}
var secret = ecoMarketClientSecretDomainService.getByTenantId(tenantId);
// 检查是否存在
if (Objects.isNull(secret)) {
log.info("Client secret missing, starting registration: tenantId={}", tenantId);
// 注册客户端
var tenantName = "EcoMarket-Client-" + tenantId;
var description = "生态市场客户端-" + tenantName;
return this.registerClientSecret(tenantId, tenantName, description);
} else {
// 已存在,直接获取
return secret;
}
}
/**
* 获取客户端密钥
*
* @return 客户端密钥DTO
*/
public ClientSecretDTO registerClientSecret(Long tenantId, String name, String description) {
if (Objects.isNull(tenantId)) {
log.error("Tenant ID cannot be empty");
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "租户ID");
}
var secret = ecoMarketClientSecretDomainService.getByTenantId(tenantId);
// 检查是否存在
if (Objects.isNull(secret)) {
log.info("Client secret missing, starting registration: tenantId={}", tenantId);
// 注册客户端
return ecoMarketClientSecretDomainService.getOrRegisterClientSecret(
tenantId,
name,
description);
} else {
// 已存在,直接获取
return secret;
}
}
}

View File

@@ -0,0 +1,24 @@
<?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-eco-market</artifactId>
<groupId>com.xspaceagi</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-eco-market-infra</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<dependencies>
<dependency>
<groupId>com.xspaceagi</groupId>
<artifactId>app-platform-eco-market-domain</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,199 @@
package com.xspaceagi.eco.market.spec.infra.dao.entity;
import java.time.LocalDateTime;
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.agent.core.adapter.repository.entity.Published;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* 生态市场配置
* @TableName eco_market_client_config
*/
@TableName(value ="eco_market_client_config")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EcoMarketClientConfig {
/**
* 主键id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 唯一ID,分布式唯一UUID
*/
private String uid;
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
private Integer dataType;
/**
* 细分类型,比如: 插件,智能体,工作流
* @see Published.TargetType
*/
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
private String categoryName;
/**
* 是否我的分享,0:否(生态市场获取的);1:是(我的分享)
*/
private Integer ownedFlag;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
private Integer shareStatus;
/**
* 使用状态,1:启用;2:禁用;
*/
private Integer useStatus;
/**
* 发布时间
*/
private LocalDateTime publishTime;
/**
* 下线时间
*/
private LocalDateTime offlineTime;
/**
* 版本号,自增,发布一次增加1,初始值为1
*/
private Long versionNumber;
/**
* 作者信息
*/
private String author;
/**
* 发布文档
*/
private String publishDoc;
/**
* 请求参数配置json
*/
private String configParamJson;
/**
* 配置json,存储插件的配置信息如果有其他额外的信息保存放这里
*/
private String configJson;
/**
* 图标图片地址
*/
private String icon;
/**
* 审批信息
*/
private String approveMessage;
/**
* 是否租户自动启用插件,1:租户自动启用;0:非租户自动启用
*/
private Boolean tenantEnabled;
/**
* 租户ID
*/
@TableField(value = "_tenant_id")
private Long tenantId;
/**
* 创建者的客户端ID
*/
private String createClientId;
/**
* 创建时间
*/
private LocalDateTime created;
/**
* 创建人id
*/
private Long creatorId;
/**
* 创建人
*/
private String creatorName;
/**
* 更新时间
*/
private LocalDateTime modified;
/**
* 最后修改人id
*/
private Long modifiedId;
/**
* 最后修改人
*/
private String modifiedName;
/**
* 逻辑标记,1:有效;-1:无效
*/
private Integer yn;
/**
* 页面压缩包地址
*/
private String pageZipUrl;
}

View File

@@ -0,0 +1,241 @@
package com.xspaceagi.eco.market.spec.infra.dao.entity;
import java.time.LocalDateTime;
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.agent.core.adapter.repository.entity.Published;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* 生态市场,客户端,已发布配置
*
* @TableName eco_market_client_publish_config
*/
@TableName(value = "eco_market_client_publish_config")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EcoMarketClientPublishConfig {
/**
* 主键id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 唯一ID,分布式唯一UUID
*/
private String uid;
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 市场类型,默认插件,1:插件;2:模板;3:MCP
*/
private Integer dataType;
/**
* 细分类型,比如: 插件,智能体,工作流
*
* @see Published.TargetType
*/
private String targetType;
/**
* 子类型
* @see Published.TargetSubType
*/
private String targetSubType;
/**
* 具体目标的id,可以智能体,工作流,插件,还有mcp等
*/
private Long targetId;
/**
* 分类编码,商业服务等,通过接口获取
*/
private String categoryCode;
/**
* 分类名称,商业服务等,通过接口获取
*/
private String categoryName;
/**
* 是否我的分享,0:否(生态市场获取的);1:是(我的分享)
*/
private Integer ownedFlag;
/**
* 分享状态,1:草稿;2:审核中;3:已发布;4:已下线;5:驳回
*/
private Integer shareStatus;
/**
* 使用状态,1:启用;2:禁用;
*/
private Integer useStatus;
/**
* 发布时间
*/
private LocalDateTime publishTime;
/**
* 下线时间
*/
private LocalDateTime offlineTime;
/**
* 版本号,自增,发布一次增加1,初始值为1
*/
private Long versionNumber;
/**
* 作者信息
*/
private String author;
/**
* 发布文档
*/
private String publishDoc;
/**
* 请求参数配置json
*/
private String configParamJson;
/**
* 配置json,存储插件的配置信息如果有其他额外的信息保存放这里
*/
private String configJson;
/**
* 图标图片地址
*/
private String icon;
/**
* 审批信息
*/
private String approveMessage;
/**
* 是否租户自动启用插件,1:租户自动启用;0:非租户自动启用
*/
private Boolean tenantEnabled;
/**
* 租户ID
*/
@TableField(value = "_tenant_id")
private Long tenantId;
/**
* 创建者的客户端ID
*/
private String createClientId;
/**
* 创建时间
*/
private LocalDateTime created;
/**
* 创建人id
*/
private Long creatorId;
/**
* 创建人
*/
private String creatorName;
/**
* 更新时间
*/
private LocalDateTime modified;
/**
* 最后修改人id
*/
private Long modifiedId;
/**
* 最后修改人
*/
private String modifiedName;
/**
* 逻辑标记,1:有效;-1:无效
*/
private Integer yn;
/**
* 页面压缩包地址
*/
private String pageZipUrl;
public static EcoMarketClientConfigModel convertToClientConfigModel(EcoMarketClientPublishConfig entity) {
EcoMarketClientConfigModel ecoMarketClientConfigModel = EcoMarketClientConfigModel.builder()
.id(entity.getId())
.uid(entity.getUid())
.name(entity.getName())
.description(entity.getDescription())
.dataType(entity.getDataType())
.targetType(entity.getTargetType())
.targetSubType(entity.getTargetSubType())
.targetId(entity.getTargetId())
.categoryCode(entity.getCategoryCode())
.categoryName(entity.getCategoryName())
.ownedFlag(entity.getOwnedFlag())
.shareStatus(entity.getShareStatus())
.useStatus(entity.getUseStatus())
.publishTime(entity.getPublishTime())
.offlineTime(entity.getOfflineTime())
.versionNumber(entity.getVersionNumber())
.author(entity.getAuthor())
.publishDoc(entity.getPublishDoc())
.configParamJson(entity.getConfigParamJson())
.localConfigParamJson(null)
.configJson(entity.getConfigJson())
.icon(entity.getIcon())
.tenantId(entity.getTenantId())
.createClientId(entity.getCreateClientId())
.created(entity.getCreated())
.creatorId(entity.getCreatorId())
.creatorName(entity.getCreatorName())
.modified(entity.getModified())
.modifiedId(entity.getModifiedId())
.modifiedName(entity.getModifiedName())
.isNewVersion(false)
.serverVersionNumber(null)
.pageZipUrl(entity.getPageZipUrl())
.build();
return ecoMarketClientConfigModel;
}
}

View File

@@ -0,0 +1,76 @@
package com.xspaceagi.eco.market.spec.infra.dao.entity;
import java.time.LocalDateTime;
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.Builder;
import lombok.Data;
/**
* 生态市场客户端密钥
*/
@Data
@TableName("eco_market_client_secret")
@Builder
public class EcoMarketClientSecret {
/**
* 主键id
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 客户端ID
*/
private String clientId;
/**
* 客户端密钥
*/
private String clientSecret;
/**
* 租户ID
*/
@TableField(value = "_tenant_id")
private Long tenantId;
/**
* 创建时间
*/
private LocalDateTime created;
/**
* 创建人id
*/
private Long creatorId;
/**
* 创建人
*/
private String creatorName;
/**
* 更新时间
*/
private LocalDateTime modified;
/**
* 逻辑标记,1:有效;-1:无效
*/
private Integer yn;
}

View File

@@ -0,0 +1,42 @@
package com.xspaceagi.eco.market.spec.infra.dao.mapper;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientConfig;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
/**
* @author soddy
* @description 针对表【eco_market_client_config(生态市场配置)】的数据库操作Mapper
* @createDate 2025-05-26 17:08:22
* @Entity com.xspaceagi.infra.dao.entity.EcoMarketClientConfig
*/
public interface EcoMarketClientConfigMapper extends BaseMapper<EcoMarketClientConfig> {
/**
* 总条数查询
*
* @param queryMap 筛选条件
* @return 总条数
*/
Long queryTotal(@Param("queryMap") Map<String, Object> queryMap);
/**
* 列表查询
*
* @param queryMap 筛选条件
* @param orderColumns 排序
* @param startIndex 索引开始位置
* @param pageSize 业务大小
* @return 列表
*/
List<EcoMarketClientConfig> queryList(@Param("queryMap") Map<String, Object> queryMap,
@Param("orderColumns") List<OrderItem> orderColumns,
@Param("startIndex") Long startIndex, @Param("pageSize") Long pageSize);
}

View File

@@ -0,0 +1,42 @@
package com.xspaceagi.eco.market.spec.infra.dao.mapper;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientPublishConfig;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
/**
* @author soddy
* @description 针对表【eco_market_client_publish_config(生态市场,客户端,已发布配置)】的数据库操作Mapper
* @createDate 2025-05-26 17:08:22
* @Entity com.xspaceagi.infra.dao.entity.EcoMarketClientPublishConfig
*/
public interface EcoMarketClientPublishConfigMapper extends BaseMapper<EcoMarketClientPublishConfig> {
/**
* 总条数查询
*
* @param queryMap 筛选条件
* @return 总条数
*/
Long queryTotal(@Param("queryMap") Map<String, Object> queryMap);
/**
* 列表查询
*
* @param queryMap 筛选条件
* @param orderColumns 排序
* @param startIndex 索引开始位置
* @param pageSize 业务大小
* @return 列表
*/
List<EcoMarketClientPublishConfig> queryList(@Param("queryMap") Map<String, Object> queryMap,
@Param("orderColumns") List<OrderItem> orderColumns,
@Param("startIndex") Long startIndex, @Param("pageSize") Long pageSize);
}

View File

@@ -0,0 +1,12 @@
package com.xspaceagi.eco.market.spec.infra.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientSecret;
import org.apache.ibatis.annotations.Mapper;
/**
* 生态市场客户端密钥Mapper
*/
@Mapper
public interface EcoMarketClientSecretMapper extends BaseMapper<EcoMarketClientSecret> {
}

View File

@@ -0,0 +1,112 @@
package com.xspaceagi.eco.market.spec.infra.dao.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientConfig;
import java.util.List;
/**
* @author soddy
* @description 针对表【eco_market_client_config(生态市场配置)】的数据库操作Service
* @createDate 2025-05-26 17:08:22
*/
public interface EcoMarketClientConfigService extends IService<EcoMarketClientConfig> {
/**
* 根据ID集合查询列表
*
* @param ids id集合
* @return 列表
*/
List<EcoMarketClientConfig> queryListByIds(List<Long> ids);
/**
* 根据主键查询 单条记录
*
* @param id id
* @return 单条记录
*/
EcoMarketClientConfig queryOneInfoById(Long id);
/**
* 更新
*
* @param entity entity
* @return id
*/
Long updateInfo(EcoMarketClientConfig entity);
/**
* 新增
*/
Long addInfo(EcoMarketClientConfig entity);
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 根据uid查询单条记录
*
* @param uid uid
* @return 单条记录
*/
EcoMarketClientConfig queryOneByUid(String uid);
/**
* 根据uid集合查询列表
*
* @param uids uid集合
* @return 列表
*/
List<EcoMarketClientConfig> queryListByUids(List<String> uids);
/**
* 根据uid更新分享状态
*
* @param uid uid
* @param shareStatus 分享状态
* @param modifiedId 修改人ID
* @return 更新结果
*/
boolean updateShareStatusByUid(String uid, Integer shareStatus, String approveMessage, Long modifiedId);
/**
* 根据uid删除配置
*
* @param uid 配置唯一标识
*/
void deleteByUid(String uid);
/**
* 查询我的分享总数
*
* @return 总数
*/
Long queryTotalMyShare();
/**
* 检查配置是否重复
*
* @param targetId 目标id
* @param targetType 目标类型
* @param dataTypeEnum 数据类型
* @param uid 配置唯一标识(可选,用于排除自身)
* @return 是否重复
*/
boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum, String uid);
/**
* 查询我的分享和审核中的配置
*
* @return 配置列表
*/
List<EcoMarketClientConfig> queryMyShareAndReviewing();
}

View File

@@ -0,0 +1,88 @@
package com.xspaceagi.eco.market.spec.infra.dao.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientPublishConfig;
import java.util.List;
/**
* @author soddy
* @description 针对表【eco_market_client_publish_config(生态市场,客户端,已发布配置)】的数据库操作Service
* @createDate 2025-05-26 17:08:22
*/
public interface EcoMarketClientPublishConfigService extends IService<EcoMarketClientPublishConfig> {
/**
* 根据ID集合查询列表
*
* @param ids id集合
* @return 列表
*/
List<EcoMarketClientPublishConfig> queryListByIds(List<Long> ids);
/**
* 根据主键查询 单条记录
*
* @param id id
* @return 单条记录
*/
EcoMarketClientPublishConfig queryOneInfoById(Long id);
/**
* 根据uid查询单条记录
*
* @param uid 配置唯一标识
* @return 单条记录
*/
EcoMarketClientPublishConfig queryOneByUid(String uid);
/**
* 更新
*
* @param entity entity
* @return id
*/
Long updateInfo(EcoMarketClientPublishConfig entity);
/**
* 新增
*/
Long addInfo(EcoMarketClientPublishConfig entity);
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 根据uid删除
*
* @param uid uid
*/
void deleteByUid(String uid);
/**
* 根据uids查询启用状态的配置
*
* @param uids 配置唯一标识列表
* @return 启用状态的配置列表
*/
List<EcoMarketClientPublishConfig> queryListByUids(List<String> uids);
/**
* 检查配置是否重复
*
* @param targetId 目标id
* @param targetType 目标类型
* @param dataTypeEnum 数据类型
* @return 是否重复
*/
boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum);
}

View File

@@ -0,0 +1,73 @@
package com.xspaceagi.eco.market.spec.infra.dao.service;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientSecret;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author soddy
* @description 针对表【eco_market_client_secret(生态市场,客户端端配置)】的数据库操作Service
* @createDate 2025-05-26 17:08:22
*/
public interface EcoMarketClientSecretService extends IService<EcoMarketClientSecret> {
/**
* 根据ID集合查询列表
*
* @param ids id集合
* @return 列表
*/
List<EcoMarketClientSecret> queryListByIds(List<Long> ids);
/**
* 根据主键查询 单条记录
*
* @param id id
* @return 单条记录
*/
EcoMarketClientSecret queryOneInfoById(Long id);
/**
* 更新
*
* @param entity entity
* @return id
*/
Long updateInfo(EcoMarketClientSecret entity);
/**
* 新增
*/
Long addInfo(EcoMarketClientSecret entity);
/**
* 删除根据主键id
*
* @param id id
*/
void deleteById(Long id);
/**
* 根据租户ID查询客户端密钥
*
* @param tenantId 租户ID
* @return 客户端密钥
*/
EcoMarketClientSecret getByTenantId(Long tenantId);
/**
* 根据客户端ID查询客户端密钥
*
* @param clientId 客户端ID
* @return 客户端密钥
*/
EcoMarketClientSecret getByClientId(String clientId);
/**
* 查询所有客户端密钥
*
* @return 客户端密钥列表
*/
List<EcoMarketClientSecret> queryAllList();
}

View File

@@ -0,0 +1,179 @@
package com.xspaceagi.eco.market.spec.infra.dao.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketOwnedFlagEnum;
import com.xspaceagi.eco.market.spec.enums.EcoMarketShareStatusEnum;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientConfig;
import com.xspaceagi.eco.market.spec.infra.dao.mapper.EcoMarketClientConfigMapper;
import com.xspaceagi.eco.market.spec.infra.dao.service.EcoMarketClientConfigService;
import com.xspaceagi.system.spec.enums.YnEnum;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.KnowledgeException;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/**
* @author soddy
* @description 针对表【eco_market_client_config(生态市场配置)】的数据库操作Service实现
* @createDate 2025-05-26 17:08:22
*/
@Service
public class EcoMarketClientConfigServiceImpl extends ServiceImpl<EcoMarketClientConfigMapper, EcoMarketClientConfig>
implements EcoMarketClientConfigService {
@Lazy
@Resource
private EcoMarketClientConfigServiceImpl self;
@Override
public List<EcoMarketClientConfig> queryListByIds(List<Long> ids) {
LambdaQueryWrapper<EcoMarketClientConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientConfig::getYn, YnEnum.Y.getKey())
.in(EcoMarketClientConfig::getId, ids);
return this.list(queryWrapper);
}
@Override
public EcoMarketClientConfig queryOneInfoById(Long id) {
LambdaQueryWrapper<EcoMarketClientConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientConfig::getYn, YnEnum.Y.getKey())
.eq(EcoMarketClientConfig::getId, id);
return this.getOne(queryWrapper);
}
@Override
public Long updateInfo(EcoMarketClientConfig entity) {
var updateObj = this.getById(entity.getId());
if (Objects.isNull(updateObj)) {
throw KnowledgeException.build(BizExceptionCodeEnum.resourceDataNotFound);
}
entity.setCreated(null);
entity.setModified(null);
this.self.updateById(entity);
return entity.getId();
}
@Override
public Long addInfo(EcoMarketClientConfig entity) {
entity.setId(null);
entity.setCreated(null);
entity.setModified(null);
this.self.save(entity);
return entity.getId();
}
@Override
public void deleteById(Long id) {
this.self.removeById(id);
}
@Override
public EcoMarketClientConfig queryOneByUid(String uid) {
if (uid == null || uid.isEmpty()) {
return null;
}
LambdaQueryWrapper<EcoMarketClientConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientConfig::getUid, uid);
queryWrapper.eq(EcoMarketClientConfig::getYn, YnEnum.Y.getKey());
return this.getOne(queryWrapper);
}
@Override
public List<EcoMarketClientConfig> queryListByUids(List<String> uids) {
if (CollectionUtils.isEmpty(uids)) {
return List.of();
}
LambdaQueryWrapper<EcoMarketClientConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(EcoMarketClientConfig::getUid, uids);
queryWrapper.eq(EcoMarketClientConfig::getYn, YnEnum.Y.getKey());
return this.list(queryWrapper);
}
@Override
public boolean updateShareStatusByUid(String uid, Integer shareStatus, String approveMessage, Long modifiedId) {
if (uid == null || uid.isEmpty() || shareStatus == null) {
return false;
}
LambdaQueryWrapper<EcoMarketClientConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientConfig::getUid, uid);
EcoMarketClientConfig updateEntity = new EcoMarketClientConfig();
updateEntity.setShareStatus(shareStatus);
updateEntity.setModified(LocalDateTime.now());
updateEntity.setApproveMessage(approveMessage);
if (modifiedId != null) {
updateEntity.setModifiedId(modifiedId);
}
return this.self.update(updateEntity, queryWrapper);
}
@Override
public void deleteByUid(String uid) {
LambdaQueryWrapper<EcoMarketClientConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientConfig::getUid, uid);
this.self.remove(queryWrapper);
}
@Override
public Long queryTotalMyShare() {
LambdaQueryWrapper<EcoMarketClientConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientConfig::getYn, YnEnum.Y.getKey());
queryWrapper.eq(EcoMarketClientConfig::getOwnedFlag, EcoMarketOwnedFlagEnum.YES.getCode());
return this.count(queryWrapper);
}
@Override
public boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum, String uid) {
LambdaQueryWrapper<EcoMarketClientConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientConfig::getYn, YnEnum.Y.getKey());
queryWrapper.eq(EcoMarketClientConfig::getTargetId, targetId);
queryWrapper.eq(EcoMarketClientConfig::getTargetType, targetType);
queryWrapper.eq(EcoMarketClientConfig::getDataType, dataTypeEnum.getCode());
queryWrapper.eq(EcoMarketClientConfig::getOwnedFlag, EcoMarketOwnedFlagEnum.YES.getCode());
// 排除自身(如果uid不为空)
if (StringUtils.isNotBlank(uid)) {
queryWrapper.ne(EcoMarketClientConfig::getUid, uid);
}
// 限制发布的配置只能有一个
queryWrapper.in(EcoMarketClientConfig::getShareStatus, EcoMarketShareStatusEnum.PUBLISHED.getCode(),
EcoMarketShareStatusEnum.REJECTED.getCode(),
EcoMarketShareStatusEnum.REVIEWING.getCode());
return this.count(queryWrapper) > 0;
}
@Override
public List<EcoMarketClientConfig> queryMyShareAndReviewing() {
LambdaQueryWrapper<EcoMarketClientConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientConfig::getYn, YnEnum.Y.getKey());
queryWrapper.eq(EcoMarketClientConfig::getOwnedFlag, EcoMarketOwnedFlagEnum.YES.getCode());
queryWrapper.eq(EcoMarketClientConfig::getShareStatus, EcoMarketShareStatusEnum.REVIEWING.getCode());
return this.list(queryWrapper);
}
}

View File

@@ -0,0 +1,113 @@
package com.xspaceagi.eco.market.spec.infra.dao.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientPublishConfig;
import com.xspaceagi.eco.market.spec.infra.dao.mapper.EcoMarketClientPublishConfigMapper;
import com.xspaceagi.eco.market.spec.infra.dao.service.EcoMarketClientPublishConfigService;
import com.xspaceagi.system.spec.enums.YnEnum;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.KnowledgeException;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
/**
* @author soddy
* @description 针对表【eco_market_client_publish_config(生态市场,客户端,已发布配置)】的数据库操作Service实现
* @createDate 2025-05-26 17:08:22
*/
@Service
public class EcoMarketClientPublishConfigServiceImpl
extends ServiceImpl<EcoMarketClientPublishConfigMapper, EcoMarketClientPublishConfig>
implements EcoMarketClientPublishConfigService {
@Lazy
@Resource
private EcoMarketClientPublishConfigServiceImpl self;
@Override
public List<EcoMarketClientPublishConfig> queryListByIds(List<Long> ids) {
LambdaQueryWrapper<EcoMarketClientPublishConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientPublishConfig::getYn, YnEnum.Y.getKey())
.in(EcoMarketClientPublishConfig::getId, ids);
return this.list(queryWrapper);
}
@Override
public EcoMarketClientPublishConfig queryOneInfoById(Long id) {
LambdaQueryWrapper<EcoMarketClientPublishConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientPublishConfig::getYn, YnEnum.Y.getKey())
.eq(EcoMarketClientPublishConfig::getId, id);
return this.getOne(queryWrapper);
}
@Override
public EcoMarketClientPublishConfig queryOneByUid(String uid) {
LambdaQueryWrapper<EcoMarketClientPublishConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientPublishConfig::getYn, YnEnum.Y.getKey())
.eq(EcoMarketClientPublishConfig::getUid, uid);
return this.getOne(queryWrapper);
}
@Override
public Long updateInfo(EcoMarketClientPublishConfig entity) {
var updateObj = this.getById(entity.getId());
if (Objects.isNull(updateObj)) {
throw KnowledgeException.build(BizExceptionCodeEnum.resourceDataNotFound);
}
entity.setCreated(null);
entity.setModified(null);
this.self.updateById(entity);
return entity.getId();
}
@Override
public Long addInfo(EcoMarketClientPublishConfig entity) {
entity.setId(null);
entity.setCreated(null);
entity.setModified(null);
this.self.save(entity);
return entity.getId();
}
@Override
public void deleteById(Long id) {
this.self.removeById(id);
}
@Override
public void deleteByUid(String uid) {
LambdaQueryWrapper<EcoMarketClientPublishConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientPublishConfig::getUid, uid);
this.self.remove(queryWrapper);
}
@Override
public List<EcoMarketClientPublishConfig> queryListByUids(List<String> uids) {
LambdaQueryWrapper<EcoMarketClientPublishConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientPublishConfig::getYn, YnEnum.Y.getKey())
.in(EcoMarketClientPublishConfig::getUid, uids);
return this.list(queryWrapper);
}
@Override
public boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum) {
LambdaQueryWrapper<EcoMarketClientPublishConfig> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientPublishConfig::getYn, YnEnum.Y.getKey());
queryWrapper.eq(EcoMarketClientPublishConfig::getTargetId, targetId);
queryWrapper.eq(EcoMarketClientPublishConfig::getTargetType, targetType);
queryWrapper.eq(EcoMarketClientPublishConfig::getDataType, dataTypeEnum.getCode());
return this.count(queryWrapper) > 0;
}
}

View File

@@ -0,0 +1,104 @@
package com.xspaceagi.eco.market.spec.infra.dao.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientSecret;
import com.xspaceagi.eco.market.spec.infra.dao.mapper.EcoMarketClientSecretMapper;
import com.xspaceagi.eco.market.spec.infra.dao.service.EcoMarketClientSecretService;
import com.xspaceagi.system.spec.enums.YnEnum;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.KnowledgeException;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
/**
* @author soddy
* @description 针对表【eco_market_client_secret(生态市场,客户端端配置)】的数据库操作Service实现
* @createDate 2025-05-26 17:08:22
*/
@Service
public class EcoMarketClientSecretServiceImpl extends ServiceImpl<EcoMarketClientSecretMapper, EcoMarketClientSecret>
implements EcoMarketClientSecretService {
@Lazy
@Resource
private EcoMarketClientSecretServiceImpl self;
@Override
public List<EcoMarketClientSecret> queryListByIds(List<Long> ids) {
LambdaQueryWrapper<EcoMarketClientSecret> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientSecret::getYn, YnEnum.Y.getKey())
.in(EcoMarketClientSecret::getId, ids);
return this.list(queryWrapper);
}
@Override
public EcoMarketClientSecret queryOneInfoById(Long id) {
LambdaQueryWrapper<EcoMarketClientSecret> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientSecret::getYn, YnEnum.Y.getKey())
.eq(EcoMarketClientSecret::getId, id);
return this.getOne(queryWrapper);
}
@Override
public Long updateInfo(EcoMarketClientSecret entity) {
var updateObj = this.getById(entity.getId());
if (Objects.isNull(updateObj)) {
throw KnowledgeException.build(BizExceptionCodeEnum.resourceDataNotFound);
}
entity.setCreated(null);
entity.setModified(null);
this.self.updateById(entity);
return entity.getId();
}
@Override
public Long addInfo(EcoMarketClientSecret entity) {
entity.setId(null);
entity.setCreated(null);
entity.setModified(null);
this.self.save(entity);
return entity.getId();
}
@Override
public void deleteById(Long id) {
this.self.removeById(id);
}
@Override
public EcoMarketClientSecret getByTenantId(Long tenantId) {
LambdaQueryWrapper<EcoMarketClientSecret> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientSecret::getTenantId, tenantId);
queryWrapper.eq(EcoMarketClientSecret::getYn, 1); // 只查询有效记录
return getOne(queryWrapper);
}
@Override
public EcoMarketClientSecret getByClientId(String clientId) {
LambdaQueryWrapper<EcoMarketClientSecret> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientSecret::getClientId, clientId);
queryWrapper.eq(EcoMarketClientSecret::getYn, 1); // 只查询有效记录
return getOne(queryWrapper);
}
@Override
public List<EcoMarketClientSecret> queryAllList() {
LambdaQueryWrapper<EcoMarketClientSecret> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EcoMarketClientSecret::getYn, YnEnum.Y.getKey());
return this.list(queryWrapper);
}
}

View File

@@ -0,0 +1,230 @@
package com.xspaceagi.eco.market.spec.infra.repository;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientConfigModel;
import com.xspaceagi.eco.market.domain.model.valueobj.QueryEcoMarketVo;
import com.xspaceagi.eco.market.domain.repository.IEcoMarketClientConfigRepository;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientConfig;
import com.xspaceagi.eco.market.spec.infra.dao.mapper.EcoMarketClientConfigMapper;
import com.xspaceagi.eco.market.spec.infra.dao.service.EcoMarketClientConfigService;
import com.xspaceagi.eco.market.spec.infra.translator.IEcoMarketClientConfigTranslator;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import com.xspaceagi.system.spec.page.PageUtils;
import com.xspaceagi.system.spec.page.SuperPage;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Repository
public class EcoMarketClientConfigRepository implements IEcoMarketClientConfigRepository {
@Resource
private IEcoMarketClientConfigTranslator ecoMarketClientConfigTranslator;
@Resource
private EcoMarketClientConfigService ecoMarketClientConfigService;
@Resource
private EcoMarketClientConfigMapper ecoMarketClientConfigMapper;
@Override
public EcoMarketClientConfigModel queryOneInfoById(Long id) {
var data = this.ecoMarketClientConfigService.queryOneInfoById(id);
if (Objects.isNull(data)) {
return null;
}
return this.ecoMarketClientConfigTranslator.convertToModel(data);
}
@Override
public List<EcoMarketClientConfigModel> queryListByIds(List<Long> ids) {
var dataList = this.ecoMarketClientConfigService.queryListByIds(ids);
return dataList.stream()
.map(ecoMarketClientConfigTranslator::convertToModel)
.collect(Collectors.toList());
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public void deleteById(Long id) {
var existObj = this.ecoMarketClientConfigService.getById(id);
if (existObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
this.ecoMarketClientConfigService.deleteById(id);
}
@Override
public Long updateInfo(EcoMarketClientConfigModel model, UserContext userContext) {
var existObj = this.ecoMarketClientConfigService.queryOneInfoById(model.getId());
if (Objects.isNull(existObj)) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
model.setCreatorId(null);
model.setCreatorName(null);
model.setModified(null);
model.setModifiedId(userContext.getUserId());
model.setModifiedName(userContext.getUserName());
var entity = this.ecoMarketClientConfigTranslator.convertToEntity(model);
entity.setId(existObj.getId());
return this.ecoMarketClientConfigService.updateInfo(entity);
}
@Override
public Long updateInfoByUid(EcoMarketClientConfigModel model, UserContext userContext) {
var existObj = this.ecoMarketClientConfigService.queryOneByUid(model.getUid());
if (Objects.isNull(existObj)) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
model.setCreatorId(null);
model.setCreatorName(null);
model.setModified(null);
model.setModifiedId(userContext.getUserId());
model.setModifiedName(userContext.getUserName());
var entity = this.ecoMarketClientConfigTranslator.convertToEntity(model);
entity.setId(existObj.getId());
return this.ecoMarketClientConfigService.updateInfo(entity);
}
@Override
public Long addInfo(EcoMarketClientConfigModel model, UserContext userContext) {
model.setId(null);
model.setCreatorId(userContext.getUserId());
model.setCreatorName(userContext.getUserName());
var entity = this.ecoMarketClientConfigTranslator.convertToEntity(model);
var id = this.ecoMarketClientConfigService.addInfo(entity);
model.setId(id);
return id;
}
@Override
public List<EcoMarketClientConfigModel> pageQuery(Map<String, Object> queryMap, List<OrderItem> orderColumns,
Long startIndex, Long pageSize) {
// 调用Mapper执行分页查询
List<EcoMarketClientConfig> entityList = ecoMarketClientConfigMapper.queryList(queryMap, orderColumns,
startIndex, pageSize);
// 转换为领域模型
if (CollectionUtils.isEmpty(entityList)) {
return List.of();
}
return entityList.stream()
.map(ecoMarketClientConfigTranslator::convertToModel)
.collect(Collectors.toList());
}
@Override
public Long queryTotal(Map<String, Object> queryMap) {
// 调用Mapper获取总数
return ecoMarketClientConfigMapper.queryTotal(queryMap);
}
@Override
public EcoMarketClientConfigModel queryOneByUid(String uid) {
EcoMarketClientConfig entity = ecoMarketClientConfigService.queryOneByUid(uid);
if (entity == null) {
return null;
}
return ecoMarketClientConfigTranslator.convertToModel(entity);
}
@Override
public List<EcoMarketClientConfigModel> queryListByUids(List<String> uids) {
List<EcoMarketClientConfig> entityList = ecoMarketClientConfigService.queryListByUids(uids);
if (CollectionUtils.isEmpty(entityList)) {
return List.of();
}
return entityList.stream()
.map(ecoMarketClientConfigTranslator::convertToModel)
.collect(Collectors.toList());
}
@Override
@DSTransactional(rollbackFor = Exception.class)
public boolean updateShareStatusByUid(String uid, Integer shareStatus, String approveMessage, UserContext userContext) {
log.info("Update share status by uid: uid={}, shareStatus={}", uid, shareStatus);
if (uid == null || uid.isEmpty()) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "配置UID");
}
if (shareStatus == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.fieldRequiredButEmpty, "分享状态");
}
Long modifiedId = null;
if (userContext != null && userContext.getUserId() != null) {
modifiedId = userContext.getUserId();
}
boolean result = ecoMarketClientConfigService.updateShareStatusByUid(uid, shareStatus, approveMessage, modifiedId);
log.info("Share status update result: uid={}, shareStatus={}, result={}", uid, shareStatus, result);
return result;
}
@Override
public IPage<EcoMarketClientConfigModel> pageQuery(QueryEcoMarketVo queryEcoMarketVo, long current, long size) {
var queryMap = new HashMap<String, Object>();
queryMap.put("dataType", queryEcoMarketVo.getDataType());
queryMap.put("categoryCode", queryEcoMarketVo.getCategoryCode());
queryMap.put("name", queryEcoMarketVo.getName());
queryMap.put("shareStatus", queryEcoMarketVo.getShareStatus());
queryMap.put("useStatus", queryEcoMarketVo.getUseStatus());
queryMap.put("ownedFlag", queryEcoMarketVo.getOwnedFlag());
queryMap.put("targetType", queryEcoMarketVo.getTargetType());
queryMap.put("targetSubType", queryEcoMarketVo.getTargetSubType());
List<OrderItem> orderColumns = new ArrayList<>();
var startIndex = PageUtils.getStartIndex(current, size);
var pageSize = PageUtils.getEndIndex(current, size);
List<EcoMarketClientConfig> entityList = ecoMarketClientConfigMapper.queryList(queryMap, orderColumns,
startIndex, pageSize);
var total = ecoMarketClientConfigMapper.queryTotal(queryMap);
var page = new SuperPage<>(current, size, total, entityList);
return page.convert(ecoMarketClientConfigTranslator::convertToModel);
}
@Override
public void deleteByUid(String uid) {
ecoMarketClientConfigService.deleteByUid(uid);
}
@Override
public Long queryTotalMyShare() {
return ecoMarketClientConfigService.queryTotalMyShare();
}
@Override
public boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum, String uid) {
return ecoMarketClientConfigService.checkConfigRepeat(targetId, targetType, dataTypeEnum, uid);
}
@Override
public List<EcoMarketClientConfigModel> queryMyShareAndReviewing() {
List<EcoMarketClientConfig> entityList = ecoMarketClientConfigService.queryMyShareAndReviewing();
return entityList.stream()
.map(ecoMarketClientConfigTranslator::convertToModel)
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,156 @@
package com.xspaceagi.eco.market.spec.infra.repository;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientPublishConfigModel;
import com.xspaceagi.eco.market.domain.model.valueobj.QueryEcoMarketVo;
import com.xspaceagi.eco.market.domain.repository.IEcoMarketClientPublishConfigRepository;
import com.xspaceagi.eco.market.spec.enums.EcoMarketDataTypeEnum;
import com.xspaceagi.eco.market.spec.infra.dao.entity.EcoMarketClientPublishConfig;
import com.xspaceagi.eco.market.spec.infra.dao.mapper.EcoMarketClientPublishConfigMapper;
import com.xspaceagi.eco.market.spec.infra.dao.service.EcoMarketClientPublishConfigService;
import com.xspaceagi.eco.market.spec.infra.translator.IEcoMarketClientPublishConfigTranslator;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.EcoMarketException;
import com.xspaceagi.system.spec.page.PageUtils;
import com.xspaceagi.system.spec.page.SuperPage;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j
@Repository
public class EcoMarketClientPublishConfigRepository implements IEcoMarketClientPublishConfigRepository {
@Resource
private IEcoMarketClientPublishConfigTranslator ecoMarketClientPublishConfigTranslator;
@Resource
private EcoMarketClientPublishConfigService ecoMarketClientPublishConfigService;
@Resource
private EcoMarketClientPublishConfigMapper ecoMarketClientPublishConfigMapper;
@Override
public EcoMarketClientPublishConfigModel queryOneInfoById(Long id) {
var data = this.ecoMarketClientPublishConfigService.queryOneInfoById(id);
if (Objects.isNull(data)) {
return null;
}
return this.ecoMarketClientPublishConfigTranslator.convertToModel(data);
}
@Override
public List<EcoMarketClientPublishConfigModel> queryListByIds(List<Long> ids) {
var dataList = this.ecoMarketClientPublishConfigService.queryListByIds(ids);
return dataList.stream()
.map(ecoMarketClientPublishConfigTranslator::convertToModel)
.collect(Collectors.toList());
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public void deleteById(Long id) {
var existObj = this.ecoMarketClientPublishConfigService.getById(id);
if (existObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
this.ecoMarketClientPublishConfigService.deleteById(id);
}
@Override
public Long updateInfo(EcoMarketClientPublishConfigModel model, UserContext userContext) {
var existObj = this.ecoMarketClientPublishConfigService.queryOneInfoById(model.getId());
if (Objects.isNull(existObj)) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
model.setCreatorId(null);
model.setCreatorName(null);
model.setModified(null);
model.setModifiedId(userContext.getUserId());
model.setModifiedName(userContext.getUserName());
var entity = this.ecoMarketClientPublishConfigTranslator.convertToEntity(model);
entity.setId(existObj.getId());
return this.ecoMarketClientPublishConfigService.updateInfo(entity);
}
@Override
public Long addInfo(EcoMarketClientPublishConfigModel model, UserContext userContext) {
model.setId(null);
model.setCreatorId(userContext.getUserId());
model.setCreatorName(userContext.getUserName());
var entity = this.ecoMarketClientPublishConfigTranslator.convertToEntity(model);
return this.ecoMarketClientPublishConfigService.addInfo(entity);
}
@Override
public EcoMarketClientPublishConfigModel queryOneByUid(String uid) {
if (uid == null || uid.isEmpty()) {
return null;
}
var data = this.ecoMarketClientPublishConfigService.queryOneByUid(uid);
if (data == null) {
return null;
}
return this.ecoMarketClientPublishConfigTranslator.convertToModel(data);
}
@Override
public IPage<EcoMarketClientPublishConfigModel> pageQuery(QueryEcoMarketVo queryEcoMarketVo, long current,
long size) {
var queryMap = new HashMap<String, Object>();
queryMap.put("dataType", queryEcoMarketVo.getDataType());
queryMap.put("categoryCode", queryEcoMarketVo.getCategoryCode());
queryMap.put("name", queryEcoMarketVo.getName());
queryMap.put("shareStatus", queryEcoMarketVo.getShareStatus());
queryMap.put("useStatus", queryEcoMarketVo.getUseStatus());
queryMap.put("ownedFlag", queryEcoMarketVo.getOwnedFlag());
queryMap.put("targetType", queryEcoMarketVo.getTargetType());
queryMap.put("targetSubType", queryEcoMarketVo.getTargetSubType());
List<OrderItem> orderColumns = new ArrayList<>();
var startIndex = PageUtils.getStartIndex(current, size);
var pageSize = PageUtils.getEndIndex(current, size);
List<EcoMarketClientPublishConfig> entityList = ecoMarketClientPublishConfigMapper.queryList(queryMap,
orderColumns, startIndex, pageSize);
var total = ecoMarketClientPublishConfigMapper.queryTotal(queryMap);
var page = new SuperPage<>(current, size, total, entityList);
return page.convert(this.ecoMarketClientPublishConfigTranslator::convertToModel);
}
@Override
public void deleteByUid(String uid) {
var existObj = this.ecoMarketClientPublishConfigService.queryOneByUid(uid);
if (existObj == null) {
throw EcoMarketException.build(BizExceptionCodeEnum.configNotFound);
}
this.ecoMarketClientPublishConfigService.deleteByUid(uid);
}
@Override
public List<EcoMarketClientPublishConfigModel> queryListByUids(List<String> uids) {
var dataList = this.ecoMarketClientPublishConfigService.queryListByUids(uids);
return dataList.stream()
.map(ecoMarketClientPublishConfigTranslator::convertToModel)
.collect(Collectors.toList());
}
@Override
public boolean checkConfigRepeat(Long targetId, String targetType, EcoMarketDataTypeEnum dataTypeEnum) {
return this.ecoMarketClientPublishConfigService.checkConfigRepeat(targetId, targetType, dataTypeEnum);
}
}

View File

@@ -0,0 +1,136 @@
package com.xspaceagi.eco.market.spec.infra.repository;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import org.springframework.stereotype.Repository;
import com.xspaceagi.eco.market.domain.model.EcoMarketClientSecretModel;
import com.xspaceagi.eco.market.domain.repository.IEcoMarketClientSecretRepository;
import com.xspaceagi.eco.market.spec.infra.dao.service.EcoMarketClientSecretService;
import com.xspaceagi.eco.market.spec.infra.translator.IEcoMarketClientSecretTranslator;
import com.xspaceagi.system.spec.common.UserContext;
import com.xspaceagi.system.spec.exception.BizExceptionCodeEnum;
import com.xspaceagi.system.spec.exception.KnowledgeException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Repository
public class EcoMarketClientSecretRepository implements IEcoMarketClientSecretRepository {
@Resource
private IEcoMarketClientSecretTranslator ecoMarketClientSecretTranslator;
@Resource
private EcoMarketClientSecretService ecoMarketClientSecretService;
@Override
public EcoMarketClientSecretModel queryOneInfoById(Long id) {
var data = this.ecoMarketClientSecretService.queryOneInfoById(id);
if (Objects.isNull(data)) {
return null;
}
return this.ecoMarketClientSecretTranslator.convertToModel(data);
}
@Override
public List<EcoMarketClientSecretModel> queryListByIds(List<Long> ids) {
var dataList = this.ecoMarketClientSecretService.queryListByIds(ids);
return dataList.stream()
.map(ecoMarketClientSecretTranslator::convertToModel)
.collect(Collectors.toList());
}
@DSTransactional(rollbackFor = Exception.class)
@Override
public void deleteById(Long id) {
var existObj = this.ecoMarketClientSecretService.getById(id);
if (existObj == null) {
throw KnowledgeException.build(BizExceptionCodeEnum.resourceDataNotFound);
}
this.ecoMarketClientSecretService.deleteById(id);
}
@Override
public Long updateInfo(EcoMarketClientSecretModel model, UserContext userContext) {
var existObj = this.ecoMarketClientSecretService.queryOneInfoById(model.getId());
if (Objects.isNull(existObj)) {
throw KnowledgeException.build(BizExceptionCodeEnum.resourceDataNotFound);
}
model.setCreatorId(null);
model.setCreatorName(null);
model.setModified(null);
var entity = this.ecoMarketClientSecretTranslator.convertToEntity(model);
entity.setId(existObj.getId());
return this.ecoMarketClientSecretService.updateInfo(entity);
}
@Override
public Long addInfo(EcoMarketClientSecretModel model, UserContext userContext) {
model.setId(null);
model.setCreatorId(userContext.getUserId());
model.setCreatorName(userContext.getUserName());
var entity = this.ecoMarketClientSecretTranslator.convertToEntity(model);
return this.ecoMarketClientSecretService.addInfo(entity);
}
@Override
public EcoMarketClientSecretModel queryByTenantId(Long tenantId) {
var data = this.ecoMarketClientSecretService.getByTenantId(tenantId);
if (Objects.isNull(data)) {
return null;
}
return this.ecoMarketClientSecretTranslator.convertToModel(data);
}
@Override
public EcoMarketClientSecretModel queryByClientId(String clientId) {
var data = this.ecoMarketClientSecretService.getByClientId(clientId);
if (Objects.isNull(data)) {
return null;
}
return this.ecoMarketClientSecretTranslator.convertToModel(data);
}
@Override
public List<EcoMarketClientSecretModel> queryListByParams(Map<String, Object> params) {
// 实际实现应该是基于参数查询,这里简化处理
log.info("Query client secrets by params: {}", params);
// 如果有tenantId参数则根据租户ID查询
if (params != null && params.containsKey("tenantId")) {
Long tenantId = (Long) params.get("tenantId");
var model = queryByTenantId(tenantId);
if (model != null) {
return List.of(model);
}
}
// 如果有clientId参数则根据客户端ID查询
if (params != null && params.containsKey("clientId")) {
String clientId = (String) params.get("clientId");
var model = queryByClientId(clientId);
if (model != null) {
return List.of(model);
}
}
// 默认返回空列表
return List.of();
}
@Override
public List<EcoMarketClientSecretModel> queryAllList() {
var dataList = this.ecoMarketClientSecretService.queryAllList();
return dataList.stream()
.map(ecoMarketClientSecretTranslator::convertToModel)
.collect(Collectors.toList());
}
}

Some files were not shown because too many files have changed in this diff Show More