Files
abot/admin/dashboard/templates/plugins_manage.html
liuwei 3a1b70d3e4 Revert "codex 试用,美化"
This reverts commit f2af83a72f.
2026-02-26 14:57:38 +08:00

385 lines
17 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}插件管理 - 机器人管理后台{% endblock %}
{% block content %}
<!-- 插件管理 -->
<div>
<el-row {% raw %}:gutter="20"{% endraw %}>
<el-col {% raw %}:span="24"{% endraw %}>
<el-card shadow="hover">
<div slot="header">
<span>插件管理</span>
<el-button style="float: right; padding: 3px 0" type="text" {% raw %}@click="refreshPlugins"{% endraw %}>
<i class="el-icon-refresh"></i> 刷新
</el-button>
</div>
<el-table {% raw %}:data="plugins"{% endraw %} style="width: 100%" border>
<el-table-column prop="name" label="插件名称"></el-table-column>
<el-table-column prop="module_name" label="模块名称"></el-table-column>
<el-table-column prop="version" label="版本"></el-table-column>
<el-table-column prop="author" label="作者"></el-table-column>
<el-table-column prop="description" label="描述" show-overflow-tooltip></el-table-column>
<el-table-column label="状态">
<template slot-scope="scope">
<el-tag {% raw %}:type="scope.row.status === 'RUNNING' ? 'success' : 'danger'"{% endraw %}>
{% raw %}{{ scope.row.status === 'RUNNING' ? '已启用' : '已禁用' }}{% endraw %}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="280">
<template slot-scope="scope">
<el-button
size="mini"
{% raw %}:type="scope.row.status === 'RUNNING' ? 'danger' : 'success'"{% endraw %}
{% raw %}@click="togglePluginStatus(scope.row)"{% endraw %}>
{% raw %}{{ scope.row.status === 'RUNNING' ? '禁用' : '启用' }}{% endraw %}
</el-button>
<el-button
size="mini"
type="primary"
{% raw %}@click="reloadPlugin(scope.row)"{% endraw %}>
重载
</el-button>
<el-button
size="mini"
type="info"
{% raw %}@click="showPluginInfo(scope.row)"{% endraw %}>
详情
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
<!-- 插件详情对话框 -->
<el-dialog title="插件详情" {% raw %}:visible.sync="pluginInfoVisible"{% endraw %} width="60%" top="5vh">
<div v-if="selectedPlugin" class="plugin-detail-container">
<el-descriptions border direction="vertical" :column="2" size="small" class="plugin-descriptions">
<el-descriptions-item label="插件名称" :span="1">{% raw %}{{ selectedPlugin.name }}{% endraw %}</el-descriptions-item>
<el-descriptions-item label="模块名称" :span="1">{% raw %}{{ selectedPlugin.module_name }}{% endraw %}</el-descriptions-item>
<el-descriptions-item label="版本" :span="1">{% raw %}{{ selectedPlugin.version }}{% endraw %}</el-descriptions-item>
<el-descriptions-item label="作者" :span="1">{% raw %}{{ selectedPlugin.author }}{% endraw %}</el-descriptions-item>
<el-descriptions-item label="状态" :span="1">
<el-tag {% raw %}:type="selectedPlugin.status === 'RUNNING' ? 'success' : 'danger'"{% endraw %} size="small">
{% raw %}{{ selectedPlugin.status === 'RUNNING' ? '已启用' : '已禁用' }}{% endraw %}
</el-tag>
</el-descriptions-item>
<el-descriptions-item label="命令前缀" :span="1" v-if="selectedPlugin.command_prefix !== undefined">
{% raw %}{{ selectedPlugin.command_prefix || '无' }}{% endraw %}
</el-descriptions-item>
<el-descriptions-item label="描述" :span="2">{% raw %}{{ selectedPlugin.description }}{% endraw %}</el-descriptions-item>
<el-descriptions-item label="命令列表" :span="2" v-if="selectedPlugin.commands && selectedPlugin.commands.length > 0">
<div class="command-tags">
<el-tag v-for="cmd in selectedPlugin.commands" :key="cmd" size="mini" style="margin-right: 5px; margin-bottom: 5px;">
{% raw %}{{ cmd }}{% endraw %}
</el-tag>
</div>
</el-descriptions-item>
<el-descriptions-item label="配置信息" :span="2" v-if="selectedPlugin.config">
<div class="config-container">
<div class="config-actions">
<el-button type="primary" size="mini" @click="editConfig" :disabled="isEditingConfig">
编辑配置
</el-button>
<el-button type="success" size="mini" @click="saveConfig" v-if="isEditingConfig">
保存配置
</el-button>
<el-button type="info" size="mini" @click="cancelEditConfig" v-if="isEditingConfig">
取消
</el-button>
</div>
<div v-if="!isEditingConfig">
<pre>{% raw %}{{ selectedPlugin.configText }}{% endraw %}</pre>
</div>
<div v-else>
<el-input
type="textarea"
v-model="editedConfig"
:rows="10"
placeholder="请输入TOML格式的配置"
class="config-editor"
></el-input>
<div class="config-error" v-if="configError">{% raw %}{{ configError }}{% endraw %}</div>
</div>
</div>
</el-descriptions-item>
</el-descriptions>
</div>
</el-dialog>
</div>
{% endblock %}
{% block scripts %}
<script>
new Vue({
el: '#app',
mixins: [baseApp],
data() {
return {
plugins: [],
selectedPlugin: null,
pluginInfoVisible: false,
loading: false,
isEditingConfig: false,
editedConfig: '',
configError: '',
configFormat: 'toml' // 默认为toml格式
}
},
mounted() {
this.currentView = '11'; // 设置当前菜单项
this.loadPlugins();
},
methods: {
loadPlugins() {
this.loading = true;
axios.get('/api/plugins')
.then(response => {
if (response.data.success) {
this.plugins = response.data.data || [];
} else {
this.$message.error(response.data.message || '加载插件列表失败');
}
})
.catch(error => {
console.error('加载插件列表出错:', error);
this.$message.error('加载插件列表出错');
})
.finally(() => {
this.loading = false;
});
},
refreshPlugins() {
this.loadPlugins();
this.$message.success('插件列表已刷新');
},
togglePluginStatus(plugin) {
const action = plugin.status === 'RUNNING' ? 'disable' : 'enable';
const actionText = plugin.status === 'RUNNING' ? '禁用' : '启用';
this.$confirm(`确定要${actionText}插件 "${plugin.name}" 吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post(`/api/plugins/${action}`, {
plugin_name: plugin.module_name
})
.then(response => {
if (response.data.success) {
this.$message.success(`${actionText}插件成功`);
this.loadPlugins(); // 重新加载插件列表
} else {
this.$message.error(response.data.message || `${actionText}插件失败`);
}
})
.catch(error => {
console.error(`${actionText}插件出错:`, error);
this.$message.error(`${actionText}插件出错`);
});
}).catch(() => {
this.$message.info('已取消操作');
});
},
reloadPlugin(plugin) {
this.$confirm(`确定要重载插件 "${plugin.name}" 吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios.post('/api/plugins/reload', {
plugin_name: plugin.module_name
})
.then(response => {
if (response.data.success) {
this.$message.success('重载插件成功');
this.loadPlugins(); // 重新加载插件列表
} else {
this.$message.error(response.data.message || '重载插件失败');
}
})
.catch(error => {
console.error('重载插件出错:', error);
this.$message.error('重载插件出错');
});
}).catch(() => {
this.$message.info('已取消操作');
});
},
// 编辑配置
editConfig() {
this.isEditingConfig = true;
this.editedConfig = this.selectedPlugin.configText || '';
this.configError = '';
},
// 取消编辑配置
cancelEditConfig() {
this.isEditingConfig = false;
this.editedConfig = '';
this.configError = '';
},
// 保存配置
saveConfig() {
try {
// 验证TOML格式
let configObj;
// 发送到后端保存
axios.post('/api/plugins/config/update', {
plugin_name: this.selectedPlugin.module_name,
config_text: this.editedConfig,
format: 'toml'
})
.then(response => {
if (response.data.success) {
this.$message.success('配置保存成功');
this.isEditingConfig = false;
// 更新本地配置显示
this.selectedPlugin.configText = this.editedConfig;
this.selectedPlugin.config = configObj;
// 询问是否要重载插件以应用新配置
this.$confirm('配置已保存,是否要重载插件以应用新配置?', '提示', {
confirmButtonText: '重载插件',
cancelButtonText: '稍后手动重载',
type: 'info'
}).then(() => {
this.reloadPlugin(this.selectedPlugin);
}).catch(() => {
this.$message.info('您可以稍后手动重载插件以应用新配置');
});
} else {
this.configError = response.data.message || '保存配置失败';
}
})
.catch(error => {
console.error('保存配置出错:', error);
this.configError = '保存配置出错: ' + (error.response?.data?.message || error.message);
});
} catch (e) {
this.configError = '处理配置时出错: ' + e.message;
}
},
// 修改现有的showPluginInfo方法获取原始配置文本
showPluginInfo(plugin) {
// 获取插件详细信息
axios.get(`/api/plugins/info?plugin_name=${plugin.module_name}`)
.then(response => {
if (response.data.success) {
this.selectedPlugin = response.data.data;
// 如果有配置文本,直接使用
if (this.selectedPlugin.configText) {
this.pluginInfoVisible = true;
this.isEditingConfig = false;
this.editedConfig = '';
this.configError = '';
return;
}
// 如果没有配置文本,获取原始配置文件内容
axios.get(`/api/plugins/config/raw?plugin_name=${plugin.module_name}`)
.then(configResponse => {
if (configResponse.data.success) {
this.selectedPlugin.configText = configResponse.data.data;
this.configFormat = configResponse.data.format || 'toml';
} else {
this.selectedPlugin.configText = '# 无法获取原始配置文件';
console.error('获取配置文件失败:', configResponse.data.message);
}
this.pluginInfoVisible = true;
this.isEditingConfig = false;
this.editedConfig = '';
this.configError = '';
})
.catch(error => {
console.error('获取配置文件出错:', error);
this.selectedPlugin.configText = '# 获取配置文件时出错';
this.pluginInfoVisible = true;
});
} else {
this.$message.error(response.data.message || '获取插件详情失败');
}
})
.catch(error => {
console.error('获取插件详情出错:', error);
this.$message.error('获取插件详情出错');
});
}
}
});
</script>
<style>
.plugin-detail-container {
max-height: 70vh;
overflow-y: auto;
}
.plugin-descriptions {
width: 100%;
}
.config-container {
max-height: 200px;
overflow-y: auto;
background-color: #f5f7fa;
border-radius: 4px;
padding: 8px;
font-size: 12px;
}
.config-container pre {
margin: 0;
white-space: pre-wrap;
word-break: break-word;
}
.command-tags {
display: flex;
flex-wrap: wrap;
}
/* 自定义滚动条样式 */
.plugin-detail-container::-webkit-scrollbar,
.config-container::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.plugin-detail-container::-webkit-scrollbar-thumb,
.config-container::-webkit-scrollbar-thumb {
background: #c0c4cc;
border-radius: 3px;
}
.plugin-detail-container::-webkit-scrollbar-track,
.config-container::-webkit-scrollbar-track {
background: #f5f7fa;
}
/* ... 现有样式保持不变 ... */
.config-actions {
margin-bottom: 10px;
display: flex;
gap: 10px;
}
.config-editor {
font-family: monospace;
font-size: 12px;
}
.config-error {
color: #f56c6c;
font-size: 12px;
margin-top: 5px;
}
</style>
{% endblock %}