mirror of
https://gitee.com/270580156/weiyu.git
synced 2025-12-30 10:52:26 +00:00
update
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.ai.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.bytedesk.core.plugin.AbstractBytedeskPlugin;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI模块插件
|
||||||
|
* 提供大模型集成、智能客服、对话生成等功能
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class AiPlugin extends AbstractBytedeskPlugin {
|
||||||
|
|
||||||
|
@Value("${bytedesk.ai.enabled:true}")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@Value("${bytedesk.ai.version:1.0.0}")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private HealthIndicator aiHealthIndicator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HealthIndicator getHealthIndicator() {
|
||||||
|
return aiHealthIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginId() {
|
||||||
|
return "ai";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginName() {
|
||||||
|
return "AI Assistant";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "AI智能助手,提供大模型集成、智能客服、对话生成、语义理解等功能";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return 15; // AI功能优先级较高
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getDependencies() {
|
||||||
|
return new String[]{"core", "kbase"}; // 依赖核心模块和知识库
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
log.info("AI Assistant Plugin initialized - Features: LLM Integration, Intelligent Q&A, Semantic Understanding");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.call.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.bytedesk.core.plugin.AbstractBytedeskPlugin;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 呼叫中心模块插件
|
||||||
|
* 提供语音通话、FreeSWITCH集成等功能
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class CallPlugin extends AbstractBytedeskPlugin {
|
||||||
|
|
||||||
|
@Value("${bytedesk.call.enabled:false}")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@Value("${bytedesk.call.version:1.0.0}")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private HealthIndicator callHealthIndicator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HealthIndicator getHealthIndicator() {
|
||||||
|
return callHealthIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginId() {
|
||||||
|
return "call";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginName() {
|
||||||
|
return "Call Center";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "呼叫中心系统,提供语音通话、FreeSWITCH集成、通话记录等功能";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return 40; // 呼叫中心优先级中等
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getDependencies() {
|
||||||
|
return new String[]{"core"}; // 依赖核心模块
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
log.info("Call Center Plugin initialized - Features: Voice Call, FreeSWITCH Integration, Call Recording");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,14 +25,10 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import com.bytedesk.core.base.BaseRestServiceWithExport;
|
import com.bytedesk.core.base.BaseRestServiceWithExport;
|
||||||
import com.bytedesk.core.constant.BytedeskConsts;
|
|
||||||
import com.bytedesk.core.constant.I18Consts;
|
import com.bytedesk.core.constant.I18Consts;
|
||||||
import com.bytedesk.core.enums.LevelEnum;
|
|
||||||
import com.bytedesk.core.exception.NotLoginException;
|
import com.bytedesk.core.exception.NotLoginException;
|
||||||
import com.bytedesk.core.rbac.user.UserEntity;
|
import com.bytedesk.core.rbac.user.UserEntity;
|
||||||
import com.bytedesk.core.uid.UidUtils;
|
import com.bytedesk.core.uid.UidUtils;
|
||||||
import com.bytedesk.core.utils.Utils;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -213,18 +209,18 @@ public class CallIvrRestService extends BaseRestServiceWithExport<CallIvrEntity,
|
|||||||
|
|
||||||
public void initCallIvrs(String orgUid) {
|
public void initCallIvrs(String orgUid) {
|
||||||
// log.info("initThreadCallIvr");
|
// log.info("initThreadCallIvr");
|
||||||
for (String tag : CallIvrInitData.getAllCallIvrs()) {
|
// for (String tag : CallIvrInitData.getAllCallIvrs()) {
|
||||||
CallIvrRequest tagRequest = CallIvrRequest.builder()
|
// CallIvrRequest tagRequest = CallIvrRequest.builder()
|
||||||
.uid(Utils.formatUid(orgUid, tag))
|
// .uid(Utils.formatUid(orgUid, tag))
|
||||||
.name(tag)
|
// .name(tag)
|
||||||
.order(0)
|
// .order(0)
|
||||||
.type(CallIvrTypeEnum.THREAD.name())
|
// .type(CallIvrTypeEnum.THREAD.name())
|
||||||
.level(LevelEnum.ORGANIZATION.name())
|
// .level(LevelEnum.ORGANIZATION.name())
|
||||||
.platform(BytedeskConsts.PLATFORM_BYTEDESK)
|
// .platform(BytedeskConsts.PLATFORM_BYTEDESK)
|
||||||
.orgUid(orgUid)
|
// .orgUid(orgUid)
|
||||||
.build();
|
// .build();
|
||||||
create(tagRequest);
|
// create(tagRequest);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.core.plugin;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.boot.actuate.health.Health;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytedesk插件抽象基类
|
||||||
|
* 提供插件的通用实现
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class AbstractBytedeskPlugin implements BytedeskPlugin {
|
||||||
|
|
||||||
|
private final Instant registerTime = Instant.now();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件作者
|
||||||
|
* 默认返回Bytedesk团队
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getAuthor() {
|
||||||
|
return "Bytedesk Team";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取健康指示器
|
||||||
|
* 子类可以重写此方法提供自定义的HealthIndicator
|
||||||
|
*/
|
||||||
|
protected HealthIndicator getHealthIndicator() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件健康状态
|
||||||
|
* 默认从对应的HealthIndicator获取
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getHealthStatus() {
|
||||||
|
Map<String, Object> status = new HashMap<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
HealthIndicator healthIndicator = getHealthIndicator();
|
||||||
|
if (healthIndicator != null) {
|
||||||
|
Health health = healthIndicator.health();
|
||||||
|
status.put("status", health.getStatus().getCode());
|
||||||
|
status.put("details", health.getDetails());
|
||||||
|
} else {
|
||||||
|
status.put("status", "UP");
|
||||||
|
status.put("message", "No health indicator configured");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to get health status for plugin: {}", getPluginId(), e);
|
||||||
|
status.put("status", "DOWN");
|
||||||
|
status.put("error", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件统计信息
|
||||||
|
* 包含基本信息和运行时长
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getStatistics() {
|
||||||
|
Map<String, Object> stats = new HashMap<>();
|
||||||
|
stats.put("pluginId", getPluginId());
|
||||||
|
stats.put("pluginName", getPluginName());
|
||||||
|
stats.put("version", getVersion());
|
||||||
|
stats.put("enabled", isEnabled());
|
||||||
|
stats.put("priority", getPriority());
|
||||||
|
stats.put("dependencies", getDependencies());
|
||||||
|
|
||||||
|
// 计算运行时长
|
||||||
|
Duration uptime = Duration.between(registerTime, Instant.now());
|
||||||
|
stats.put("uptime-seconds", uptime.getSeconds());
|
||||||
|
stats.put("uptime-readable", formatDuration(uptime));
|
||||||
|
stats.put("registerTime", registerTime.toString());
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时长
|
||||||
|
*/
|
||||||
|
protected String formatDuration(Duration duration) {
|
||||||
|
long days = duration.toDays();
|
||||||
|
long hours = duration.toHoursPart();
|
||||||
|
long minutes = duration.toMinutesPart();
|
||||||
|
return String.format("%dd %dh %dm", days, hours, minutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件初始化
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
log.info("Initializing plugin: {} ({})", getPluginName(), getPluginId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件销毁
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
log.info("Destroying plugin: {} ({})", getPluginName(), getPluginId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.core.plugin;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bytedesk插件接口
|
||||||
|
* 所有模块插件必须实现此接口
|
||||||
|
*/
|
||||||
|
public interface BytedeskPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件唯一标识符
|
||||||
|
* @return 插件ID,如:kbase, service, ticket, ai, call, voc
|
||||||
|
*/
|
||||||
|
String getPluginId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件名称
|
||||||
|
* @return 插件显示名称
|
||||||
|
*/
|
||||||
|
String getPluginName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件描述
|
||||||
|
* @return 插件功能描述
|
||||||
|
*/
|
||||||
|
String getDescription();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件版本
|
||||||
|
* @return 版本号
|
||||||
|
*/
|
||||||
|
String getVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件作者
|
||||||
|
* @return 作者信息
|
||||||
|
*/
|
||||||
|
String getAuthor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件官网
|
||||||
|
* @return 官网URL
|
||||||
|
*/
|
||||||
|
default String getWebsite() {
|
||||||
|
return "https://bytedesk.com";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件是否启用
|
||||||
|
* @return true表示启用,false表示禁用
|
||||||
|
*/
|
||||||
|
boolean isEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件优先级(数字越小优先级越高)
|
||||||
|
* @return 优先级值,默认100
|
||||||
|
*/
|
||||||
|
default int getPriority() {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件依赖的其他插件ID列表
|
||||||
|
* @return 依赖的插件ID数组,如果没有依赖返回空数组
|
||||||
|
*/
|
||||||
|
default String[] getDependencies() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件健康状态
|
||||||
|
* @return 健康状态信息
|
||||||
|
*/
|
||||||
|
Map<String, Object> getHealthStatus();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件统计信息
|
||||||
|
* @return 统计数据
|
||||||
|
*/
|
||||||
|
default Map<String, Object> getStatistics() {
|
||||||
|
return Map.of(
|
||||||
|
"enabled", isEnabled(),
|
||||||
|
"version", getVersion()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件初始化
|
||||||
|
* 在插件注册后调用
|
||||||
|
*/
|
||||||
|
default void initialize() {
|
||||||
|
// 默认空实现
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件销毁
|
||||||
|
* 在应用关闭时调用
|
||||||
|
*/
|
||||||
|
default void destroy() {
|
||||||
|
// 默认空实现
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.core.plugin;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心模块插件
|
||||||
|
* 提供基础功能:用户管理、权限控制、消息系统等
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class CorePlugin extends AbstractBytedeskPlugin {
|
||||||
|
|
||||||
|
@Value("${bytedesk.core.enabled:true}")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@Value("${bytedesk.core.version:1.0.0}")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private HealthIndicator coreHealthIndicator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HealthIndicator getHealthIndicator() {
|
||||||
|
return coreHealthIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginId() {
|
||||||
|
return "core";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginName() {
|
||||||
|
return "Core Module";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "核心模块,提供用户管理、权限控制、消息系统、通知等基础功能";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return 1; // 核心模块优先级最高
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getDependencies() {
|
||||||
|
return new String[0]; // 核心模块不依赖其他模块
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
log.info("Core Module Plugin initialized - Features: User Management, RBAC, Messaging, Notification");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.core.plugin;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件管理控制器
|
||||||
|
* 提供插件信息查询和管理接口
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/plugins")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "Plugin Management", description = "插件管理接口")
|
||||||
|
public class PluginController {
|
||||||
|
|
||||||
|
private final PluginRegistry pluginRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有插件列表
|
||||||
|
* http://127.0.0.1:9003/api/v1/plugins
|
||||||
|
*/
|
||||||
|
@GetMapping
|
||||||
|
@Operation(summary = "获取所有插件", description = "获取系统中所有已注册的插件列表")
|
||||||
|
public ResponseEntity<Map<String, Object>> getAllPlugins() {
|
||||||
|
List<BytedeskPlugin> plugins = pluginRegistry.getAllPlugins();
|
||||||
|
|
||||||
|
List<Map<String, Object>> pluginList = plugins.stream()
|
||||||
|
.sorted(Comparator.comparingInt(BytedeskPlugin::getPriority))
|
||||||
|
.map(this::convertPluginToMap)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Map<String, Object> response = new LinkedHashMap<>();
|
||||||
|
response.put("total", plugins.size());
|
||||||
|
response.put("enabled", pluginRegistry.getEnabledPluginCount());
|
||||||
|
response.put("plugins", pluginList);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取已启用的插件列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/enabled")
|
||||||
|
@Operation(summary = "获取已启用插件", description = "获取系统中所有已启用的插件列表")
|
||||||
|
public ResponseEntity<Map<String, Object>> getEnabledPlugins() {
|
||||||
|
List<BytedeskPlugin> plugins = pluginRegistry.getEnabledPlugins();
|
||||||
|
|
||||||
|
List<Map<String, Object>> pluginList = plugins.stream()
|
||||||
|
.map(this::convertPluginToMap)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
Map<String, Object> response = new LinkedHashMap<>();
|
||||||
|
response.put("total", plugins.size());
|
||||||
|
response.put("plugins", pluginList);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定插件信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/{pluginId}")
|
||||||
|
@Operation(summary = "获取插件详情", description = "根据插件ID获取插件详细信息")
|
||||||
|
public ResponseEntity<Map<String, Object>> getPlugin(@PathVariable String pluginId) {
|
||||||
|
Optional<BytedeskPlugin> plugin = pluginRegistry.getPlugin(pluginId);
|
||||||
|
|
||||||
|
if (plugin.isEmpty()) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> response = convertPluginToDetailMap(plugin.get());
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件健康状态
|
||||||
|
*/
|
||||||
|
@GetMapping("/{pluginId}/health")
|
||||||
|
@Operation(summary = "获取插件健康状态", description = "获取指定插件的健康检查状态")
|
||||||
|
public ResponseEntity<Map<String, Object>> getPluginHealth(@PathVariable String pluginId) {
|
||||||
|
Optional<BytedeskPlugin> plugin = pluginRegistry.getPlugin(pluginId);
|
||||||
|
|
||||||
|
if (plugin.isEmpty()) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> health = plugin.get().getHealthStatus();
|
||||||
|
return ResponseEntity.ok(health);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有插件的健康状态
|
||||||
|
*/
|
||||||
|
@GetMapping("/health")
|
||||||
|
@Operation(summary = "获取所有插件健康状态", description = "获取系统中所有插件的健康检查状态")
|
||||||
|
public ResponseEntity<Map<String, Object>> getAllPluginsHealth() {
|
||||||
|
Map<String, Map<String, Object>> healthStatus = pluginRegistry.getAllPluginsHealthStatus();
|
||||||
|
|
||||||
|
Map<String, Object> response = new LinkedHashMap<>();
|
||||||
|
response.put("timestamp", System.currentTimeMillis());
|
||||||
|
response.put("total", pluginRegistry.getPluginCount());
|
||||||
|
response.put("enabled", pluginRegistry.getEnabledPluginCount());
|
||||||
|
response.put("plugins", healthStatus);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件统计信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/{pluginId}/statistics")
|
||||||
|
@Operation(summary = "获取插件统计信息", description = "获取指定插件的统计数据")
|
||||||
|
public ResponseEntity<Map<String, Object>> getPluginStatistics(@PathVariable String pluginId) {
|
||||||
|
Optional<BytedeskPlugin> plugin = pluginRegistry.getPlugin(pluginId);
|
||||||
|
|
||||||
|
if (plugin.isEmpty()) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> statistics = plugin.get().getStatistics();
|
||||||
|
return ResponseEntity.ok(statistics);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有插件的统计信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/statistics")
|
||||||
|
@Operation(summary = "获取所有插件统计信息", description = "获取系统中所有插件的统计数据")
|
||||||
|
public ResponseEntity<Map<String, Object>> getAllPluginsStatistics() {
|
||||||
|
Map<String, Map<String, Object>> statistics = pluginRegistry.getAllPluginsStatistics();
|
||||||
|
|
||||||
|
Map<String, Object> response = new LinkedHashMap<>();
|
||||||
|
response.put("timestamp", System.currentTimeMillis());
|
||||||
|
response.put("total", pluginRegistry.getPluginCount());
|
||||||
|
response.put("enabled", pluginRegistry.getEnabledPluginCount());
|
||||||
|
response.put("plugins", statistics);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件概览信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/overview")
|
||||||
|
@Operation(summary = "获取插件概览", description = "获取插件系统的概览信息")
|
||||||
|
public ResponseEntity<Map<String, Object>> getPluginsOverview() {
|
||||||
|
Map<String, Object> overview = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// 基本统计
|
||||||
|
overview.put("totalPlugins", pluginRegistry.getPluginCount());
|
||||||
|
overview.put("enabledPlugins", pluginRegistry.getEnabledPluginCount());
|
||||||
|
overview.put("disabledPlugins", pluginRegistry.getPluginCount() - pluginRegistry.getEnabledPluginCount());
|
||||||
|
|
||||||
|
// 插件列表(简化信息)
|
||||||
|
List<Map<String, Object>> pluginSummary = pluginRegistry.getAllPlugins().stream()
|
||||||
|
.sorted(Comparator.comparingInt(BytedeskPlugin::getPriority))
|
||||||
|
.map(plugin -> {
|
||||||
|
Map<String, Object> summary = new LinkedHashMap<>();
|
||||||
|
summary.put("id", plugin.getPluginId());
|
||||||
|
summary.put("name", plugin.getPluginName());
|
||||||
|
summary.put("version", plugin.getVersion());
|
||||||
|
summary.put("enabled", plugin.isEnabled());
|
||||||
|
summary.put("priority", plugin.getPriority());
|
||||||
|
return summary;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
overview.put("plugins", pluginSummary);
|
||||||
|
|
||||||
|
return ResponseEntity.ok(overview);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换插件为Map(简化版)
|
||||||
|
*/
|
||||||
|
private Map<String, Object> convertPluginToMap(BytedeskPlugin plugin) {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
map.put("id", plugin.getPluginId());
|
||||||
|
map.put("name", plugin.getPluginName());
|
||||||
|
map.put("description", plugin.getDescription());
|
||||||
|
map.put("version", plugin.getVersion());
|
||||||
|
map.put("enabled", plugin.isEnabled());
|
||||||
|
map.put("priority", plugin.getPriority());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换插件为Map(详细版)
|
||||||
|
*/
|
||||||
|
private Map<String, Object> convertPluginToDetailMap(BytedeskPlugin plugin) {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
map.put("id", plugin.getPluginId());
|
||||||
|
map.put("name", plugin.getPluginName());
|
||||||
|
map.put("description", plugin.getDescription());
|
||||||
|
map.put("version", plugin.getVersion());
|
||||||
|
map.put("author", plugin.getAuthor());
|
||||||
|
map.put("website", plugin.getWebsite());
|
||||||
|
map.put("enabled", plugin.isEnabled());
|
||||||
|
map.put("priority", plugin.getPriority());
|
||||||
|
map.put("dependencies", plugin.getDependencies());
|
||||||
|
map.put("statistics", plugin.getStatistics());
|
||||||
|
map.put("health", plugin.getHealthStatus());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,284 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.core.plugin;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件注册中心
|
||||||
|
* 管理所有Bytedesk模块插件的注册、查询和生命周期
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class PluginRegistry {
|
||||||
|
|
||||||
|
private final Map<String, BytedeskPlugin> plugins = new ConcurrentHashMap<>();
|
||||||
|
private final List<BytedeskPlugin> pluginList;
|
||||||
|
|
||||||
|
public PluginRegistry(List<BytedeskPlugin> pluginList) {
|
||||||
|
this.pluginList = pluginList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化:自动注册所有插件
|
||||||
|
*/
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
log.info("Initializing Plugin Registry...");
|
||||||
|
|
||||||
|
// 按优先级排序
|
||||||
|
List<BytedeskPlugin> sortedPlugins = pluginList.stream()
|
||||||
|
.sorted(Comparator.comparingInt(BytedeskPlugin::getPriority))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 注册所有插件
|
||||||
|
for (BytedeskPlugin plugin : sortedPlugins) {
|
||||||
|
registerPlugin(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Plugin Registry initialized with {} plugins", plugins.size());
|
||||||
|
logRegisteredPlugins();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册插件
|
||||||
|
*/
|
||||||
|
public void registerPlugin(BytedeskPlugin plugin) {
|
||||||
|
if (plugin == null) {
|
||||||
|
log.warn("Attempted to register null plugin");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String pluginId = plugin.getPluginId();
|
||||||
|
if (pluginId == null || pluginId.trim().isEmpty()) {
|
||||||
|
log.error("Plugin ID cannot be null or empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查依赖
|
||||||
|
if (!checkDependencies(plugin)) {
|
||||||
|
log.error("Plugin {} has unmet dependencies", pluginId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册插件
|
||||||
|
plugins.put(pluginId, plugin);
|
||||||
|
log.info("Registered plugin: {} ({}) - Version: {}, Enabled: {}",
|
||||||
|
plugin.getPluginName(), pluginId, plugin.getVersion(), plugin.isEnabled());
|
||||||
|
|
||||||
|
// 初始化插件
|
||||||
|
try {
|
||||||
|
plugin.initialize();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to initialize plugin: {}", pluginId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注销插件
|
||||||
|
*/
|
||||||
|
public void unregisterPlugin(String pluginId) {
|
||||||
|
BytedeskPlugin plugin = plugins.remove(pluginId);
|
||||||
|
if (plugin != null) {
|
||||||
|
try {
|
||||||
|
plugin.destroy();
|
||||||
|
log.info("Unregistered plugin: {} ({})", plugin.getPluginName(), pluginId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to destroy plugin: {}", pluginId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件
|
||||||
|
*/
|
||||||
|
public Optional<BytedeskPlugin> getPlugin(String pluginId) {
|
||||||
|
return Optional.ofNullable(plugins.get(pluginId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有插件
|
||||||
|
*/
|
||||||
|
public List<BytedeskPlugin> getAllPlugins() {
|
||||||
|
return new ArrayList<>(plugins.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有已启用的插件
|
||||||
|
*/
|
||||||
|
public List<BytedeskPlugin> getEnabledPlugins() {
|
||||||
|
return plugins.values().stream()
|
||||||
|
.filter(BytedeskPlugin::isEnabled)
|
||||||
|
.sorted(Comparator.comparingInt(BytedeskPlugin::getPriority))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件数量
|
||||||
|
*/
|
||||||
|
public int getPluginCount() {
|
||||||
|
return plugins.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取已启用插件数量
|
||||||
|
*/
|
||||||
|
public int getEnabledPluginCount() {
|
||||||
|
return (int) plugins.values().stream()
|
||||||
|
.filter(BytedeskPlugin::isEnabled)
|
||||||
|
.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查插件是否存在
|
||||||
|
*/
|
||||||
|
public boolean hasPlugin(String pluginId) {
|
||||||
|
return plugins.containsKey(pluginId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查插件是否启用
|
||||||
|
*/
|
||||||
|
public boolean isPluginEnabled(String pluginId) {
|
||||||
|
return getPlugin(pluginId)
|
||||||
|
.map(BytedeskPlugin::isEnabled)
|
||||||
|
.orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有插件的健康状态
|
||||||
|
*/
|
||||||
|
public Map<String, Map<String, Object>> getAllPluginsHealthStatus() {
|
||||||
|
Map<String, Map<String, Object>> healthStatus = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
plugins.values().stream()
|
||||||
|
.sorted(Comparator.comparingInt(BytedeskPlugin::getPriority))
|
||||||
|
.forEach(plugin -> {
|
||||||
|
try {
|
||||||
|
healthStatus.put(plugin.getPluginId(), plugin.getHealthStatus());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to get health status for plugin: {}", plugin.getPluginId(), e);
|
||||||
|
healthStatus.put(plugin.getPluginId(), Map.of(
|
||||||
|
"status", "ERROR",
|
||||||
|
"error", e.getMessage()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return healthStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有插件的统计信息
|
||||||
|
*/
|
||||||
|
public Map<String, Map<String, Object>> getAllPluginsStatistics() {
|
||||||
|
Map<String, Map<String, Object>> statistics = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
plugins.values().stream()
|
||||||
|
.sorted(Comparator.comparingInt(BytedeskPlugin::getPriority))
|
||||||
|
.forEach(plugin -> {
|
||||||
|
try {
|
||||||
|
statistics.put(plugin.getPluginId(), plugin.getStatistics());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to get statistics for plugin: {}", plugin.getPluginId(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return statistics;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查插件依赖是否满足
|
||||||
|
*/
|
||||||
|
private boolean checkDependencies(BytedeskPlugin plugin) {
|
||||||
|
String[] dependencies = plugin.getDependencies();
|
||||||
|
if (dependencies == null || dependencies.length == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String dependency : dependencies) {
|
||||||
|
if (!plugins.containsKey(dependency)) {
|
||||||
|
log.warn("Plugin {} depends on {}, but it's not registered yet",
|
||||||
|
plugin.getPluginId(), dependency);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录已注册的插件信息
|
||||||
|
*/
|
||||||
|
private void logRegisteredPlugins() {
|
||||||
|
if (plugins.isEmpty()) {
|
||||||
|
log.warn("No plugins registered");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("==================================================");
|
||||||
|
log.info("Registered Plugins ({})", plugins.size());
|
||||||
|
log.info("==================================================");
|
||||||
|
|
||||||
|
plugins.values().stream()
|
||||||
|
.sorted(Comparator.comparingInt(BytedeskPlugin::getPriority))
|
||||||
|
.forEach(plugin -> {
|
||||||
|
log.info(" - {} ({}) v{} [{}] Priority: {}",
|
||||||
|
plugin.getPluginName(),
|
||||||
|
plugin.getPluginId(),
|
||||||
|
plugin.getVersion(),
|
||||||
|
plugin.isEnabled() ? "ENABLED" : "DISABLED",
|
||||||
|
plugin.getPriority());
|
||||||
|
|
||||||
|
String[] deps = plugin.getDependencies();
|
||||||
|
if (deps != null && deps.length > 0) {
|
||||||
|
log.info(" Dependencies: {}", String.join(", ", deps));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
log.info("==================================================");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁:注销所有插件
|
||||||
|
*/
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
log.info("Destroying Plugin Registry...");
|
||||||
|
|
||||||
|
// 按优先级逆序销毁
|
||||||
|
List<BytedeskPlugin> sortedPlugins = new ArrayList<>(plugins.values());
|
||||||
|
sortedPlugins.sort(Comparator.comparingInt(BytedeskPlugin::getPriority).reversed());
|
||||||
|
|
||||||
|
for (BytedeskPlugin plugin : sortedPlugins) {
|
||||||
|
try {
|
||||||
|
plugin.destroy();
|
||||||
|
log.info("Destroyed plugin: {}", plugin.getPluginId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to destroy plugin: {}", plugin.getPluginId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins.clear();
|
||||||
|
log.info("Plugin Registry destroyed");
|
||||||
|
}
|
||||||
|
}
|
||||||
353
modules/core/src/main/java/com/bytedesk/core/plugin/README.md
Normal file
353
modules/core/src/main/java/com/bytedesk/core/plugin/README.md
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
# Bytedesk 插件系统
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
Bytedesk 插件系统提供了一个统一的框架来管理各个功能模块,实现模块化架构和集中管理。
|
||||||
|
|
||||||
|
## 架构设计
|
||||||
|
|
||||||
|
### 核心组件
|
||||||
|
|
||||||
|
1. **BytedeskPlugin 接口** - 定义插件的基本契约
|
||||||
|
2. **AbstractBytedeskPlugin** - 提供插件的通用实现
|
||||||
|
3. **PluginRegistry** - 插件注册中心,管理所有插件
|
||||||
|
4. **PluginController** - REST API 接口,提供插件信息查询
|
||||||
|
|
||||||
|
### 插件生命周期
|
||||||
|
|
||||||
|
```
|
||||||
|
注册 -> 初始化 -> 运行 -> 销毁
|
||||||
|
```
|
||||||
|
|
||||||
|
## 已注册插件
|
||||||
|
|
||||||
|
| 插件ID | 名称 | 描述 | 优先级 | 依赖 |
|
||||||
|
|--------|------|------|--------|------|
|
||||||
|
| service | Customer Service | 在线客服系统 | 10 | core |
|
||||||
|
| ai | AI Assistant | AI智能助手 | 15 | core, kbase |
|
||||||
|
| kbase | Knowledge Base | 知识库管理 | 20 | core |
|
||||||
|
| ticket | Ticket System | 工单管理系统 | 30 | core |
|
||||||
|
| call | Call Center | 呼叫中心 | 40 | core |
|
||||||
|
| voc | Voice of Customer | 客户之声 | 50 | core |
|
||||||
|
|
||||||
|
## API 接口
|
||||||
|
|
||||||
|
### 1. 获取所有插件
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/plugins
|
||||||
|
```
|
||||||
|
|
||||||
|
**响应示例:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"total": 6,
|
||||||
|
"enabled": 5,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"id": "service",
|
||||||
|
"name": "Customer Service",
|
||||||
|
"description": "在线客服系统,提供实时聊天、会话管理、客服分配、消息队列等功能",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"enabled": true,
|
||||||
|
"priority": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 获取插件概览
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/plugins/overview
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 获取插件详情
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/plugins/{pluginId}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 获取插件健康状态
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/plugins/{pluginId}/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 获取所有插件健康状态
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/plugins/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 获取插件统计信息
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/plugins/{pluginId}/statistics
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. 获取所有插件统计信息
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /api/v1/plugins/statistics
|
||||||
|
```
|
||||||
|
|
||||||
|
## 创建自定义插件
|
||||||
|
|
||||||
|
### 步骤 1: 创建插件类
|
||||||
|
|
||||||
|
```java
|
||||||
|
package com.bytedesk.yourmodule.plugin;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import com.bytedesk.core.plugin.AbstractBytedeskPlugin;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class YourModulePlugin extends AbstractBytedeskPlugin {
|
||||||
|
|
||||||
|
@Value("${bytedesk.yourmodule.enabled:true}")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@Value("${bytedesk.yourmodule.version:1.0.0}")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private HealthIndicator yourModuleHealthIndicator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HealthIndicator getHealthIndicator() {
|
||||||
|
return yourModuleHealthIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginId() {
|
||||||
|
return "yourmodule";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginName() {
|
||||||
|
return "Your Module Name";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Your module description";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return 100; // 设置优先级
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getDependencies() {
|
||||||
|
return new String[]{"core"}; // 设置依赖
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 步骤 2: 配置文件
|
||||||
|
|
||||||
|
在 `application.yml` 中添加:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
bytedesk:
|
||||||
|
yourmodule:
|
||||||
|
enabled: true
|
||||||
|
version: 1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### 步骤 3: 创建健康检查器(可选)
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class YourModuleHealthIndicator implements HealthIndicator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Health health() {
|
||||||
|
try {
|
||||||
|
// 执行健康检查逻辑
|
||||||
|
return Health.up()
|
||||||
|
.withDetail("status", "Running")
|
||||||
|
.build();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Health.down()
|
||||||
|
.withDetail("error", e.getMessage())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 插件优先级
|
||||||
|
|
||||||
|
优先级数值越小,优先级越高。建议范围:
|
||||||
|
|
||||||
|
- **1-10**: 核心功能(如 service)
|
||||||
|
- **11-20**: 重要功能(如 ai)
|
||||||
|
- **21-30**: 常规功能(如 kbase)
|
||||||
|
- **31-50**: 辅助功能(如 ticket, call, voc)
|
||||||
|
- **51-100**: 扩展功能
|
||||||
|
|
||||||
|
## 插件依赖
|
||||||
|
|
||||||
|
插件可以声明依赖其他插件:
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Override
|
||||||
|
public String[] getDependencies() {
|
||||||
|
return new String[]{"core", "kbase"};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
插件注册中心会在注册时检查依赖是否满足。
|
||||||
|
|
||||||
|
## 配置选项
|
||||||
|
|
||||||
|
### 启用/禁用插件
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
bytedesk:
|
||||||
|
kbase:
|
||||||
|
enabled: true # 启用知识库插件
|
||||||
|
call:
|
||||||
|
enabled: false # 禁用呼叫中心插件
|
||||||
|
```
|
||||||
|
|
||||||
|
### 设置插件版本
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
bytedesk:
|
||||||
|
service:
|
||||||
|
version: 1.2.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## 监控和管理
|
||||||
|
|
||||||
|
### 通过 Actuator 端点
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看应用健康状态(包含所有模块)
|
||||||
|
curl http://localhost:9003/actuator/health
|
||||||
|
|
||||||
|
# 查看特定模块健康状态
|
||||||
|
curl http://localhost:9003/actuator/health/kbase
|
||||||
|
curl http://localhost:9003/actuator/health/service
|
||||||
|
```
|
||||||
|
|
||||||
|
### 通过插件 API
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看插件概览
|
||||||
|
curl http://localhost:9003/api/v1/plugins/overview
|
||||||
|
|
||||||
|
# 查看所有插件健康状态
|
||||||
|
curl http://localhost:9003/api/v1/plugins/health
|
||||||
|
|
||||||
|
# 查看特定插件详情
|
||||||
|
curl http://localhost:9003/api/v1/plugins/kbase
|
||||||
|
```
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
1. **命名规范**
|
||||||
|
- 插件ID:使用小写字母,如 `kbase`, `service`
|
||||||
|
- 类名:使用 PascalCase + Plugin 后缀,如 `KbasePlugin`
|
||||||
|
|
||||||
|
2. **版本管理**
|
||||||
|
- 使用语义化版本号:`major.minor.patch`
|
||||||
|
- 在配置文件中集中管理版本
|
||||||
|
|
||||||
|
3. **健康检查**
|
||||||
|
- 为每个插件提供健康检查器
|
||||||
|
- 检查关键资源(数据库、缓存、外部服务等)
|
||||||
|
|
||||||
|
4. **依赖管理**
|
||||||
|
- 明确声明插件依赖
|
||||||
|
- 避免循环依赖
|
||||||
|
|
||||||
|
5. **错误处理**
|
||||||
|
- 插件初始化失败不应影响其他插件
|
||||||
|
- 提供详细的错误信息和日志
|
||||||
|
|
||||||
|
## 故障排查
|
||||||
|
|
||||||
|
### 插件未注册
|
||||||
|
|
||||||
|
**问题:** 插件列表中看不到某个插件
|
||||||
|
|
||||||
|
**排查步骤:**
|
||||||
|
1. 检查插件类是否添加了 `@Component` 注解
|
||||||
|
2. 检查插件类所在包是否被扫描
|
||||||
|
3. 查看启动日志中的插件注册信息
|
||||||
|
4. 检查插件是否被配置为禁用状态
|
||||||
|
|
||||||
|
### 依赖检查失败
|
||||||
|
|
||||||
|
**问题:** 插件因依赖问题注册失败
|
||||||
|
|
||||||
|
**排查步骤:**
|
||||||
|
1. 检查依赖的插件是否已注册
|
||||||
|
2. 查看插件注册顺序(按优先级)
|
||||||
|
3. 确认依赖关系是否正确
|
||||||
|
|
||||||
|
### 健康检查失败
|
||||||
|
|
||||||
|
**问题:** 插件健康状态为 DOWN
|
||||||
|
|
||||||
|
**排查步骤:**
|
||||||
|
1. 检查 HealthIndicator 实现
|
||||||
|
2. 查看健康检查错误日志
|
||||||
|
3. 确认相关资源(数据库、Redis 等)是否正常
|
||||||
|
|
||||||
|
## 示例代码
|
||||||
|
|
||||||
|
### 获取插件信息
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Autowired
|
||||||
|
private PluginRegistry pluginRegistry;
|
||||||
|
|
||||||
|
// 获取所有插件
|
||||||
|
List<BytedeskPlugin> plugins = pluginRegistry.getAllPlugins();
|
||||||
|
|
||||||
|
// 获取特定插件
|
||||||
|
Optional<BytedeskPlugin> plugin = pluginRegistry.getPlugin("kbase");
|
||||||
|
|
||||||
|
// 检查插件是否启用
|
||||||
|
boolean isEnabled = pluginRegistry.isPluginEnabled("service");
|
||||||
|
|
||||||
|
// 获取插件健康状态
|
||||||
|
Map<String, Object> health = plugin.get().getHealthStatus();
|
||||||
|
```
|
||||||
|
|
||||||
|
## 未来扩展
|
||||||
|
|
||||||
|
- [ ] 插件热加载/卸载
|
||||||
|
- [ ] 插件配置动态更新
|
||||||
|
- [ ] 插件间通信机制
|
||||||
|
- [ ] 插件市场
|
||||||
|
- [ ] 插件权限管理
|
||||||
|
|
||||||
|
## 相关文档
|
||||||
|
|
||||||
|
- [Health Indicator 文档](https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints.health)
|
||||||
|
- [Spring Boot Actuator](https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html)
|
||||||
|
- [模块化架构设计](./ARCHITECTURE.md)
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
Business Source License 1.1 - https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.kbase.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.bytedesk.core.plugin.AbstractBytedeskPlugin;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 知识库模块插件
|
||||||
|
* 提供知识库、文章、FAQ、向量检索等功能
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class KbasePlugin extends AbstractBytedeskPlugin {
|
||||||
|
|
||||||
|
@Value("${bytedesk.kbase.enabled:true}")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@Value("${bytedesk.kbase.version:1.0.0}")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private HealthIndicator kbaseHealthIndicator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HealthIndicator getHealthIndicator() {
|
||||||
|
return kbaseHealthIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginId() {
|
||||||
|
return "kbase";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginName() {
|
||||||
|
return "Knowledge Base";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "知识库管理系统,提供文章、FAQ、智能问答、向量检索等功能";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return 20; // 知识库优先级较高
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getDependencies() {
|
||||||
|
return new String[]{"core"}; // 依赖核心模块
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
log.info("Knowledge Base Plugin initialized - Features: Article, FAQ, Vector Search, AI Integration");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.service.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.bytedesk.core.plugin.AbstractBytedeskPlugin;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在线客服模块插件
|
||||||
|
* 提供实时聊天、会话管理、客服分配等功能
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class ServicePlugin extends AbstractBytedeskPlugin {
|
||||||
|
|
||||||
|
@Value("${bytedesk.service.enabled:true}")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@Value("${bytedesk.service.version:1.0.0}")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private HealthIndicator serviceHealthIndicator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HealthIndicator getHealthIndicator() {
|
||||||
|
return serviceHealthIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginId() {
|
||||||
|
return "service";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginName() {
|
||||||
|
return "Customer Service";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "在线客服系统,提供实时聊天、会话管理、客服分配、消息队列等功能";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return 10; // 客服是核心功能,优先级最高
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getDependencies() {
|
||||||
|
return new String[]{"core"}; // 依赖核心模块
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
log.info("Customer Service Plugin initialized - Features: Live Chat, Session Management, Agent Assignment");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.ticket.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.bytedesk.core.plugin.AbstractBytedeskPlugin;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工单系统模块插件
|
||||||
|
* 提供工单管理、工单流转、SLA等功能
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class TicketPlugin extends AbstractBytedeskPlugin {
|
||||||
|
|
||||||
|
@Value("${bytedesk.ticket.enabled:true}")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@Value("${bytedesk.ticket.version:1.0.0}")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private HealthIndicator ticketHealthIndicator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HealthIndicator getHealthIndicator() {
|
||||||
|
return ticketHealthIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginId() {
|
||||||
|
return "ticket";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginName() {
|
||||||
|
return "Ticket System";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "工单管理系统,提供工单创建、分配、流转、SLA管理等功能";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return 30; // 工单系统优先级中等
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getDependencies() {
|
||||||
|
return new String[]{"core"}; // 依赖核心模块
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
log.info("Ticket System Plugin initialized - Features: Ticket Management, Workflow, SLA");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* @Author: jackning 270580156@qq.com
|
||||||
|
* @Date: 2025-10-06 10:00:00
|
||||||
|
* @LastEditors: jackning 270580156@qq.com
|
||||||
|
* @LastEditTime: 2025-10-06 10:00:00
|
||||||
|
* @Description: bytedesk.com https://github.com/Bytedesk/bytedesk
|
||||||
|
* Please be aware of the BSL license restrictions before installing Bytedesk IM –
|
||||||
|
* selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license.
|
||||||
|
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||||
|
* contact: 270580156@qq.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||||
|
*/
|
||||||
|
package com.bytedesk.voc.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import com.bytedesk.core.plugin.AbstractBytedeskPlugin;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户之声模块插件
|
||||||
|
* 提供客户反馈、满意度调查、数据分析等功能
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class VocPlugin extends AbstractBytedeskPlugin {
|
||||||
|
|
||||||
|
@Value("${bytedesk.voc.enabled:true}")
|
||||||
|
private boolean enabled;
|
||||||
|
|
||||||
|
@Value("${bytedesk.voc.version:1.0.0}")
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private HealthIndicator vocHealthIndicator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HealthIndicator getHealthIndicator() {
|
||||||
|
return vocHealthIndicator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginId() {
|
||||||
|
return "voc";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPluginName() {
|
||||||
|
return "Voice of Customer";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "客户之声系统,提供客户反馈收集、满意度调查、数据分析、报表生成等功能";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPriority() {
|
||||||
|
return 50; // VOC优先级较低
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getDependencies() {
|
||||||
|
return new String[]{"core"}; // 依赖核心模块
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
log.info("Voice of Customer Plugin initialized - Features: Feedback Collection, Satisfaction Survey, Analytics");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user