diff --git a/astrbot/core/star/star_manager.py b/astrbot/core/star/star_manager.py
index 7a49807f6..abdedc249 100644
--- a/astrbot/core/star/star_manager.py
+++ b/astrbot/core/star/star_manager.py
@@ -680,11 +680,18 @@ class PluginManager:
return plugin_info
- async def uninstall_plugin(self, plugin_name: str):
+ async def uninstall_plugin(
+ self,
+ plugin_name: str,
+ delete_config: bool = False,
+ delete_data: bool = False,
+ ):
"""卸载指定的插件。
Args:
plugin_name (str): 要卸载的插件名称
+ delete_config (bool): 是否删除插件配置文件,默认为 False
+ delete_data (bool): 是否删除插件数据,默认为 False
Raises:
Exception: 当插件不存在、是保留插件时,或删除插件文件夹失败时抛出异常
@@ -714,6 +721,7 @@ class PluginManager:
await self._unbind_plugin(plugin_name, plugin.module_path)
+ # 删除插件文件夹
try:
remove_dir(os.path.join(ppath, root_dir_name))
except Exception as e:
@@ -721,6 +729,51 @@ class PluginManager:
f"移除插件成功,但是删除插件文件夹失败: {e!s}。您可以手动删除该文件夹,位于 addons/plugins/ 下。",
)
+ # 删除插件配置文件
+ if delete_config and root_dir_name:
+ config_file = os.path.join(
+ self.plugin_config_path,
+ f"{root_dir_name}_config.json",
+ )
+ if os.path.exists(config_file):
+ try:
+ os.remove(config_file)
+ logger.info(f"已删除插件 {plugin_name} 的配置文件")
+ except Exception as e:
+ logger.warning(f"删除插件配置文件失败: {e!s}")
+
+ # 删除插件持久化数据
+ # 注意:需要检查两个可能的目录名(plugin_data 和 plugins_data)
+ # data/temp 目录可能被多个插件共享,不自动删除以防误删
+ if delete_data and root_dir_name:
+ data_base_dir = os.path.dirname(ppath) # data/
+
+ # 删除 data/plugin_data 下的插件持久化数据(单数形式,新版本)
+ plugin_data_dir = os.path.join(
+ data_base_dir, "plugin_data", root_dir_name
+ )
+ if os.path.exists(plugin_data_dir):
+ try:
+ remove_dir(plugin_data_dir)
+ logger.info(
+ f"已删除插件 {plugin_name} 的持久化数据 (plugin_data)"
+ )
+ except Exception as e:
+ logger.warning(f"删除插件持久化数据失败 (plugin_data): {e!s}")
+
+ # 删除 data/plugins_data 下的插件持久化数据(复数形式,旧版本兼容)
+ plugins_data_dir = os.path.join(
+ data_base_dir, "plugins_data", root_dir_name
+ )
+ if os.path.exists(plugins_data_dir):
+ try:
+ remove_dir(plugins_data_dir)
+ logger.info(
+ f"已删除插件 {plugin_name} 的持久化数据 (plugins_data)"
+ )
+ except Exception as e:
+ logger.warning(f"删除插件持久化数据失败 (plugins_data): {e!s}")
+
async def _unbind_plugin(self, plugin_name: str, plugin_module_path: str):
"""解绑并移除一个插件。
diff --git a/astrbot/dashboard/routes/plugin.py b/astrbot/dashboard/routes/plugin.py
index 71b238dd7..597a245d4 100644
--- a/astrbot/dashboard/routes/plugin.py
+++ b/astrbot/dashboard/routes/plugin.py
@@ -395,9 +395,15 @@ class PluginRoute(Route):
post_data = await request.json
plugin_name = post_data["name"]
+ delete_config = post_data.get("delete_config", False)
+ delete_data = post_data.get("delete_data", False)
try:
logger.info(f"正在卸载插件 {plugin_name}")
- await self.plugin_manager.uninstall_plugin(plugin_name)
+ await self.plugin_manager.uninstall_plugin(
+ plugin_name,
+ delete_config=delete_config,
+ delete_data=delete_data,
+ )
logger.info(f"卸载插件 {plugin_name} 成功")
return Response().ok(None, "卸载成功").__dict__
except Exception as e:
diff --git a/dashboard/src/components/shared/ExtensionCard.vue b/dashboard/src/components/shared/ExtensionCard.vue
index 4af11cc7a..a74b40cba 100644
--- a/dashboard/src/components/shared/ExtensionCard.vue
+++ b/dashboard/src/components/shared/ExtensionCard.vue
@@ -2,6 +2,7 @@
import { ref, computed, inject } from 'vue';
import { useCustomizerStore } from "@/stores/customizer";
import { useModuleI18n } from '@/i18n/composables';
+import UninstallConfirmDialog from './UninstallConfirmDialog.vue';
const props = defineProps({
extension: {
@@ -31,6 +32,7 @@ const emit = defineEmits([
]);
const reveal = ref(false);
+const showUninstallDialog = ref(false);
// 国际化
const { tm } = useModuleI18n('features/extension');
@@ -55,19 +57,11 @@ const installExtension = async () => {
};
const uninstallExtension = async () => {
- if (typeof $confirm !== "function") {
- console.error(tm("card.errors.confirmNotRegistered"));
- return;
- }
+ showUninstallDialog.value = true;
+};
- const confirmed = await $confirm({
- title: tm("dialogs.uninstall.title"),
- message: tm("dialogs.uninstall.message"),
- });
-
- if (confirmed) {
- emit("uninstall", props.extension);
- }
+const handleUninstallConfirm = (options: { deleteConfig: boolean; deleteData: boolean }) => {
+ emit("uninstall", props.extension, options);
};
const toggleActivation = () => {
@@ -220,6 +214,12 @@ const viewReadme = () => {
+
+
+