feat: 脚本管理页面(类似青龙面板)
Some checks failed
continuous-integration/drone/push Build is failing

- 新增脚本管理页面,左右分栏布局
- 集成 Monaco Editor 代码编辑器(语法高亮、行号、快捷键)
- 支持脚本 CRUD、运行、复制等操作
- 定时任务支持从脚本库导入脚本
- 新增 platform_scripts 表存储脚本
This commit is contained in:
2026-01-28 13:13:08 +08:00
parent 9b72e6127f
commit 2f9d85edb6
8 changed files with 1372 additions and 2 deletions

View File

@@ -48,6 +48,11 @@ const form = reactive({
const templateList = ref([])
const templateDialogVisible = ref(false)
// 脚本库
const scriptLibList = ref([])
const scriptLibDialogVisible = ref(false)
const scriptLibLoading = ref(false)
// 版本
const versionsDialogVisible = ref(false)
const versionsLoading = ref(false)
@@ -433,6 +438,33 @@ function applyTemplate(template) {
ElMessage.success(`已应用模板:${template.name}`)
}
// ============ 脚本库功能 ============
async function handleSelectFromScriptLib() {
scriptLibLoading.value = true
scriptLibDialogVisible.value = true
try {
const res = await api.get('/api/scripts', { params: { size: 100 } })
scriptLibList.value = res.data.items || []
} catch (e) {
console.error('获取脚本库失败:', e)
} finally {
scriptLibLoading.value = false
}
}
async function applyScriptFromLib(script) {
try {
// 获取脚本完整内容
const res = await api.get(`/api/scripts/${script.id}`)
form.script_content = res.data.script_content || ''
scriptLibDialogVisible.value = false
ElMessage.success(`已导入脚本:${script.name}`)
} catch (e) {
console.error(e)
}
}
// ============ 版本功能 ============
async function handleViewVersions(row) {
currentVersionTaskId.value = row.id
@@ -739,11 +771,14 @@ onMounted(() => {
<div class="script-editor-header">
<div>
<el-button type="primary" link size="small" @click="handleShowSdkDocs">
查看 SDK 文档
SDK 文档
</el-button>
<el-button type="warning" link size="small" @click="handleSelectTemplate">
选择模板
</el-button>
<el-button type="success" link size="small" @click="handleSelectFromScriptLib">
从脚本库导入
</el-button>
</div>
<el-button
type="success"
@@ -929,6 +964,46 @@ log('执行完成')"
</template>
</el-dialog>
<!-- 脚本库选择对话框 -->
<el-dialog v-model="scriptLibDialogVisible" title="从脚本库导入" width="700px">
<div v-loading="scriptLibLoading">
<div v-if="scriptLibList.length === 0 && !scriptLibLoading" class="empty-tip">
暂无脚本请先在脚本管理页面创建
</div>
<div v-else class="script-lib-list">
<div
v-for="script in scriptLibList"
:key="script.id"
class="script-lib-item"
@click="applyScriptFromLib(script)"
>
<div class="script-lib-header">
<span class="script-lib-name">{{ script.name }}</span>
<el-tag v-if="script.category" size="small" type="info">{{ script.category }}</el-tag>
<el-tag
v-if="script.last_run_status"
size="small"
:type="script.last_run_status === 'success' ? 'success' : 'danger'"
>
{{ script.last_run_status }}
</el-tag>
</div>
<div class="script-lib-desc">{{ script.description || '暂无描述' }}</div>
<div class="script-lib-meta">
<span>{{ script.filename }}</span>
<span v-if="script.content_length">{{ script.content_length }} 字符</span>
</div>
</div>
</div>
</div>
<template #footer>
<el-button @click="scriptLibDialogVisible = false">取消</el-button>
<el-button type="primary" @click="$router.push('/scripts')">
管理脚本库
</el-button>
</template>
</el-dialog>
<!-- 版本管理对话框 -->
<el-dialog v-model="versionsDialogVisible" title="脚本版本历史" width="700px">
<el-table v-loading="versionsLoading" :data="versionsList" style="width: 100%">
@@ -1206,6 +1281,51 @@ log('执行完成')"
padding: 40px 0;
}
/* 脚本库列表 */
.script-lib-list {
max-height: 450px;
overflow-y: auto;
}
.script-lib-item {
padding: 12px 16px;
border: 1px solid #e4e7ed;
border-radius: 8px;
margin-bottom: 8px;
cursor: pointer;
transition: all 0.2s;
}
.script-lib-item:hover {
border-color: #67c23a;
background: #f0f9eb;
}
.script-lib-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
}
.script-lib-name {
font-weight: 600;
color: #303133;
}
.script-lib-desc {
font-size: 12px;
color: #606266;
margin-bottom: 6px;
}
.script-lib-meta {
display: flex;
gap: 16px;
font-size: 11px;
color: #909399;
}
/* 统计 */
.stats-grid {
display: grid;