diff --git a/astrbot/dashboard/routes/plugin.py b/astrbot/dashboard/routes/plugin.py index e369ad054..81d9b0bfe 100644 --- a/astrbot/dashboard/routes/plugin.py +++ b/astrbot/dashboard/routes/plugin.py @@ -1,5 +1,6 @@ import traceback import aiohttp +import os import ssl import certifi @@ -36,6 +37,7 @@ class PluginRoute(Route): "/plugin/off": ("POST", self.off_plugin), "/plugin/on": ("POST", self.on_plugin), "/plugin/reload": ("POST", self.reload_plugins), + "/plugin/readme": ("GET", self.get_plugin_readme), } self.core_lifecycle = core_lifecycle self.plugin_manager = plugin_manager @@ -317,3 +319,42 @@ class PluginRoute(Route): except Exception as e: logger.error(f"/api/plugin/on: {traceback.format_exc()}") return Response().error(str(e)).__dict__ + + async def get_plugin_readme(self): + plugin_name = request.args.get("name") + logger.debug(f"正在获取插件 {plugin_name} 的README文件内容") + + if not plugin_name: + logger.warning("插件名称为空") + return Response().error("插件名称不能为空").__dict__ + + plugin_obj = None + for plugin in self.plugin_manager.context.get_all_stars(): + if plugin.name == plugin_name: + plugin_obj = plugin + break + + if not plugin_obj: + logger.warning(f"插件 {plugin_name} 不存在") + return Response().error(f"插件 {plugin_name} 不存在").__dict__ + + plugin_dir = os.path.join(self.plugin_manager.plugin_store_path, plugin_obj.root_dir_name) + + if not os.path.isdir(plugin_dir): + logger.warning(f"无法找到插件目录: {plugin_dir}") + return Response().error(f"无法找到插件 {plugin_name} 的目录").__dict__ + + readme_path = os.path.join(plugin_dir, "README.md") + + if not os.path.isfile(readme_path): + logger.warning(f"插件 {plugin_name} 没有README文件") + return Response().error(f"插件 {plugin_name} 没有README文件").__dict__ + + try: + with open(readme_path, 'r', encoding='utf-8') as f: + readme_content = f.read() + + return Response().ok({"content": readme_content}, "成功获取README内容").__dict__ + except Exception as e: + logger.error(f"/api/plugin/readme: {traceback.format_exc()}") + return Response().error(f"读取README文件失败: {str(e)}").__dict__ diff --git a/dashboard/src/components/shared/ExtensionCard.vue b/dashboard/src/components/shared/ExtensionCard.vue index 18f845646..e6573260c 100644 --- a/dashboard/src/components/shared/ExtensionCard.vue +++ b/dashboard/src/components/shared/ExtensionCard.vue @@ -24,13 +24,10 @@ const emit = defineEmits([ 'install', 'uninstall', 'toggle-activation', - 'view-handlers' + 'view-handlers', + 'view-readme' ]); -const open = (link: string | undefined) => { - window.open(link, '_blank'); -}; - const reveal = ref(false); // 操作函数 @@ -70,6 +67,10 @@ const toggleActivation = () => { const viewHandlers = () => { emit('view-handlers', props.extension); }; + +const viewReadme = () => { + emit('view-readme', props.extension); +}; @@ -128,7 +129,7 @@ const viewHandlers = () => { - + diff --git a/dashboard/src/components/shared/ReadmeDialog.vue b/dashboard/src/components/shared/ReadmeDialog.vue new file mode 100644 index 000000000..292575291 --- /dev/null +++ b/dashboard/src/components/shared/ReadmeDialog.vue @@ -0,0 +1,302 @@ + + + + + + + 插件说明文档 + + mdi-close + + + + + + + 在GitHub中查看仓库 + + + 刷新文档 + + + + + + + 正在加载README文档... + + + + + + + + mdi-alert-circle-outline + {{ error }} + + + + + mdi-file-question-outline + 该插件未提供文档链接或GitHub仓库地址。请查看插件市场或联系插件作者获取更多信息。 + + + + + + + 关闭 + + + + + + + + + \ No newline at end of file diff --git a/dashboard/src/views/ExtensionMarketplace.vue b/dashboard/src/views/ExtensionMarketplace.vue index 6fbce072a..f8c14c540 100644 --- a/dashboard/src/views/ExtensionMarketplace.vue +++ b/dashboard/src/views/ExtensionMarketplace.vue @@ -88,6 +88,13 @@ import 'highlight.js/styles/github.css'; }} {{ item.author }} + + + 无 {{ tag @@ -262,6 +269,7 @@ export default { { title: '名称', key: 'name', maxWidth: '150px' }, { title: '描述', key: 'desc', maxWidth: '250px' }, { title: '作者', key: 'author', maxWidth: '60px' }, + { title: 'Star数', key: 'stars', maxWidth: '100px' }, { title: '标签', key: 'tags', maxWidth: '60px' }, { title: '操作', key: 'actions', sortable: false } ], diff --git a/dashboard/src/views/ExtensionPage.vue b/dashboard/src/views/ExtensionPage.vue index 1b1171b1e..33f78dd01 100644 --- a/dashboard/src/views/ExtensionPage.vue +++ b/dashboard/src/views/ExtensionPage.vue @@ -3,6 +3,7 @@ import ExtensionCard from '@/components/shared/ExtensionCard.vue'; import WaitingForRestart from '@/components/shared/WaitingForRestart.vue'; import AstrBotConfig from '@/components/shared/AstrBotConfig.vue'; import ConsoleDisplayer from '@/components/shared/ConsoleDisplayer.vue'; +import ReadmeDialog from '@/components/shared/ReadmeDialog.vue'; import axios from 'axios'; import { useCommonStore } from '@/stores/common'; @@ -35,6 +36,12 @@ const selectedPlugin = ref({}); const curr_namespace = ref(""); const wfr = ref(null); +const readmeDialog = reactive({ + show: false, + pluginName: '', + repoUrl: null +}); + const plugin_handler_info_headers = [ { title: '行为类型', key: 'event_type_h' }, { title: '描述', key: 'desc', maxWidth: '250px' }, @@ -225,6 +232,12 @@ const reloadPlugin = async (plugin_name) => { } }; +const viewReadme = (plugin) => { + readmeDialog.pluginName = plugin.name; + readmeDialog.repoUrl = plugin.repo; + readmeDialog.show = true; +}; + // 生命周期 onMounted(async () => { await getExtensions(); @@ -279,7 +292,8 @@ onMounted(async () => { @update="updateExtension(extension.name)" @reload="reloadPlugin(extension.name)" @toggle-activation="extension.activated ? pluginOff(extension) : pluginOn(extension)" - @view-handlers="showPluginInfo(extension)"> + @view-handlers="showPluginInfo(extension)" + @view-readme="viewReadme(extension)"> @@ -365,4 +379,10 @@ onMounted(async () => { + + \ No newline at end of file
正在加载README文档...
{{ error }}
该插件未提供文档链接或GitHub仓库地址。请查看插件市场或联系插件作者获取更多信息。