686 lines
31 KiB
HTML
686 lines
31 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Cocos ECS Extension - 热更新管理后台</title>
|
||
<link href="https://cdn.jsdelivr.net/npm/element-plus@2.4.4/dist/index.css" rel="stylesheet">
|
||
<style>
|
||
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
|
||
.header { background: #409eff; color: white; padding: 16px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
||
.container { max-width: 1200px; margin: 20px auto; padding: 0 20px; }
|
||
.card { background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); margin-bottom: 20px; }
|
||
.upload-area {
|
||
border: 2px dashed #dcdfe6;
|
||
border-radius: 8px;
|
||
padding: 40px;
|
||
text-align: center;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
}
|
||
.upload-area:hover { border-color: #409eff; background: #f0f8ff; }
|
||
.version-list { max-height: 400px; overflow-y: auto; }
|
||
.version-item {
|
||
padding: 16px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
.version-info h4 { margin: 0 0 8px 0; color: #303133; }
|
||
.version-info p { margin: 0; color: #909399; font-size: 14px; }
|
||
.status-tag {
|
||
padding: 4px 12px;
|
||
border-radius: 16px;
|
||
font-size: 12px;
|
||
font-weight: bold;
|
||
}
|
||
.status-active { background: #f0f9ff; color: #409eff; }
|
||
.status-draft { background: #fdf6ec; color: #e6a23c; }
|
||
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; }
|
||
.stat-card {
|
||
padding: 24px;
|
||
text-align: center;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
border-radius: 12px;
|
||
}
|
||
.stat-number { font-size: 32px; font-weight: bold; margin-bottom: 8px; }
|
||
.stat-label { font-size: 14px; opacity: 0.9; }
|
||
.btn {
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
transition: all 0.3s;
|
||
}
|
||
.btn-primary { background: #409eff; color: white; }
|
||
.btn-primary:hover { background: #337ecc; }
|
||
.btn-danger { background: #f56c6c; color: white; }
|
||
.btn-danger:hover { background: #dd6161; }
|
||
.btn-success { background: #67c23a; color: white; }
|
||
.btn-success:hover { background: #5daf34; }
|
||
.plugin-card:hover { border-color: #409eff; background: #f0f8ff; }
|
||
.plugin-active { border-color: #409eff !important; background: #f0f8ff !important; }
|
||
.filtered-out { opacity: 0.3; }
|
||
|
||
/* 模态框样式 */
|
||
.modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.modal-content {
|
||
background: white;
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||
width: 600px;
|
||
max-width: 90%;
|
||
max-height: 90%;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.modal-header {
|
||
padding: 20px 24px;
|
||
border-bottom: 1px solid #e4e7ed;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.modal-header h3 {
|
||
margin: 0;
|
||
color: #303133;
|
||
}
|
||
|
||
.modal-close {
|
||
background: none;
|
||
border: none;
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
color: #909399;
|
||
padding: 0;
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.modal-close:hover {
|
||
background: #f5f7fa;
|
||
color: #606266;
|
||
}
|
||
|
||
.modal-body {
|
||
padding: 24px;
|
||
}
|
||
|
||
.modal-footer {
|
||
padding: 20px 24px;
|
||
border-top: 1px solid #e4e7ed;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 12px;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.form-group label {
|
||
display: block;
|
||
margin-bottom: 8px;
|
||
color: #606266;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.form-group small {
|
||
display: block;
|
||
margin-top: 4px;
|
||
color: #909399;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.btn.btn-default {
|
||
background: #fff;
|
||
color: #606266;
|
||
border: 1px solid #dcdfe6;
|
||
}
|
||
|
||
.btn.btn-default:hover {
|
||
color: #409eff;
|
||
border-color: #c6e2ff;
|
||
background: #ecf5ff;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="app">
|
||
<div class="header">
|
||
<h1 style="margin: 0; font-size: 24px;">🚀 Cocos ECS Extension - 热更新管理后台</h1>
|
||
</div>
|
||
|
||
<div class="container">
|
||
<!-- 插件选择器 -->
|
||
<div class="card">
|
||
<div style="padding: 20px;">
|
||
<h2>🔌 插件管理</h2>
|
||
<div style="display: flex; gap: 20px; flex-wrap: wrap;">
|
||
<div
|
||
v-for="plugin in plugins"
|
||
:key="plugin.id"
|
||
@click="selectPlugin(plugin.id)"
|
||
:class="'plugin-card ' + (currentPlugin === plugin.id ? 'plugin-active' : '')"
|
||
style="flex: 1; min-width: 250px; padding: 20px; border: 2px solid #e4e7ed; border-radius: 8px; cursor: pointer; transition: all 0.3s;"
|
||
>
|
||
<div style="display: flex; align-items: center; gap: 12px;">
|
||
<span style="font-size: 32px;">{{ plugin.icon }}</span>
|
||
<div style="flex: 1;">
|
||
<h3 style="margin: 0; color: #303133;">{{ plugin.displayName }}</h3>
|
||
<p style="margin: 4px 0 0 0; color: #909399; font-size: 14px;">{{ plugin.description || '暂无描述' }}</p>
|
||
<div style="margin: 8px 0 0 0; display: flex; gap: 16px; font-size: 12px;">
|
||
<span style="color: #67c23a;">{{ plugin.status === 'active' ? '✅ 活跃' : '⏸️ 暂停' }}</span>
|
||
<span style="color: #409eff;">📦 版本: {{ plugin.versionCount || 0 }}</span>
|
||
<span style="color: #e6a23c;">📥 下载: {{ plugin.totalDownloads || 0 }}</span>
|
||
</div>
|
||
<p style="margin: 4px 0 0 0; color: #c0c4cc; font-size: 12px;">{{ plugin.author || '未知作者' }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 统计数据 -->
|
||
<div class="card">
|
||
<div style="padding: 20px;">
|
||
<h2>📊 系统统计</h2>
|
||
<div class="stats-grid">
|
||
<div class="stat-card">
|
||
<div class="stat-number">{{ stats.totalVersions }}</div>
|
||
<div class="stat-label">总版本数</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number">{{ stats.activeUsers }}</div>
|
||
<div class="stat-label">活跃用户</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number">{{ stats.todayUpdates }}</div>
|
||
<div class="stat-label">今日更新</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-number">{{ stats.successRate }}%</div>
|
||
<div class="stat-label">成功率</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 上传新版本 -->
|
||
<div class="card">
|
||
<div style="padding: 20px;">
|
||
<h2>📦 上传新版本</h2>
|
||
<div class="upload-area" @click="selectFile">
|
||
<div v-if="!uploading">
|
||
<i style="font-size: 48px; color: #c0c4cc;">📁</i>
|
||
<p style="margin: 16px 0 0 0; color: #606266;">点击或拖拽文件到此处上传插件包</p>
|
||
<p style="margin: 8px 0 0 0; color: #909399; font-size: 14px;">支持 .zip 格式,最大 100MB</p>
|
||
</div>
|
||
<div v-else>
|
||
<i style="font-size: 48px; color: #409eff;">⏳</i>
|
||
<p style="margin: 16px 0 0 0; color: #409eff;">上传中... {{ uploadProgress }}%</p>
|
||
</div>
|
||
</div>
|
||
<input type="file" ref="fileInput" @change="handleFileSelect" accept=".zip" style="display: none;">
|
||
|
||
<div v-if="selectedFile" style="margin-top: 20px; padding: 16px; background: #f5f7fa; border-radius: 4px;">
|
||
<h4 style="margin: 0 0 12px 0;">版本信息</h4>
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
|
||
<div>
|
||
<label>目标插件:</label>
|
||
<select v-model="versionInfo.pluginId" style="width: 100%; padding: 8px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
<option v-for="plugin in plugins" :key="plugin.id" :value="plugin.id">
|
||
{{ plugin.icon }} {{ plugin.displayName }}
|
||
</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label>版本号:</label>
|
||
<input v-model="versionInfo.version" style="width: 100%; padding: 8px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
</div>
|
||
<div>
|
||
<label>发布渠道:</label>
|
||
<select v-model="versionInfo.channel" style="width: 100%; padding: 8px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
<option value="stable">稳定版</option>
|
||
<option value="beta">测试版</option>
|
||
<option value="dev">开发版</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top: 16px;">
|
||
<label>更新说明:</label>
|
||
<textarea v-model="versionInfo.description" rows="3" style="width: 100%; padding: 8px; border: 1px solid #dcdfe6; border-radius: 4px;"></textarea>
|
||
</div>
|
||
<div style="margin-top: 16px;">
|
||
<label>
|
||
<input type="checkbox" v-model="versionInfo.mandatory"> 强制更新
|
||
</label>
|
||
</div>
|
||
<div style="margin-top: 16px;">
|
||
<button class="btn btn-primary" @click="uploadVersion" :disabled="uploading">
|
||
{{ uploading ? '上传中...' : '发布版本' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 版本管理 -->
|
||
<div class="card">
|
||
<div style="padding: 20px;">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||
<h2>📋 版本管理 - {{ getCurrentPluginName() }}</h2>
|
||
<div style="display: flex; gap: 12px; align-items: center;">
|
||
<button class="btn btn-primary" @click="showCreatePlugin = true">+ 创建新项目</button>
|
||
<select v-model="currentPlugin" @change="filterVersions" style="padding: 8px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
<option value="">全部插件</option>
|
||
<option v-for="plugin in plugins" :key="plugin.id" :value="plugin.id">
|
||
{{ plugin.icon }} {{ plugin.displayName }}
|
||
</option>
|
||
</select>
|
||
<button class="btn btn-success" @click="refreshVersions">刷新列表</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="version-list">
|
||
<div v-for="version in filteredVersions" :key="version.id" class="version-item">
|
||
<div class="version-info">
|
||
<h4>
|
||
<span style="margin-right: 8px;">{{ getPluginIcon(version.pluginId) }}</span>
|
||
{{ version.version }} ({{ getChannelName(version.channel) }})
|
||
<span style="font-size: 12px; color: #909399; margin-left: 8px;">- {{ getPluginDisplayName(version.pluginId) }}</span>
|
||
</h4>
|
||
<p>{{ version.description }}</p>
|
||
<p>发布时间: {{ formatDate(version.release_date) }} | 文件大小: {{ formatSize(version.file_size) }}</p>
|
||
</div>
|
||
<div style="display: flex; align-items: center; gap: 12px;">
|
||
<span :class="'status-tag status-' + version.status">
|
||
{{ getStatusName(version.status) }}
|
||
</span>
|
||
<button class="btn btn-primary" @click="editVersion(version)">编辑</button>
|
||
<button class="btn btn-danger" @click="deleteVersion(version)">删除</button>
|
||
</div>
|
||
</div>
|
||
<div v-if="filteredVersions.length === 0" style="text-align: center; padding: 40px; color: #909399;">
|
||
{{ currentPlugin ? '该插件暂无版本数据' : '暂无版本数据' }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 创建项目模态框 -->
|
||
<div v-if="showCreatePlugin" class="modal-overlay" @click="showCreatePlugin = false">
|
||
<div class="modal-content" @click.stop>
|
||
<div class="modal-header">
|
||
<h3>🎯 创建新项目</h3>
|
||
<button @click="showCreatePlugin = false" class="modal-close">×</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="form-group">
|
||
<label>项目ID *</label>
|
||
<input v-model="newPlugin.id" placeholder="例如: my-awesome-plugin" style="width: 100%; padding: 12px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
<small>项目ID必须是唯一的,建议使用小写字母和短横线</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>项目名称 *</label>
|
||
<input v-model="newPlugin.name" placeholder="例如: my-awesome-plugin" style="width: 100%; padding: 12px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>显示名称 *</label>
|
||
<input v-model="newPlugin.displayName" placeholder="例如: My Awesome Plugin" style="width: 100%; padding: 12px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>项目描述</label>
|
||
<textarea v-model="newPlugin.description" rows="3" placeholder="描述你的项目功能和特点..." style="width: 100%; padding: 12px; border: 1px solid #dcdfe6; border-radius: 4px;"></textarea>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>作者</label>
|
||
<input v-model="newPlugin.author" placeholder="例如: Your Name" style="width: 100%; padding: 12px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>仓库地址</label>
|
||
<input v-model="newPlugin.repository" placeholder="例如: https://github.com/user/repo" style="width: 100%; padding: 12px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>图标 (Emoji)</label>
|
||
<input v-model="newPlugin.icon" placeholder="📦" maxlength="2" style="width: 100%; padding: 12px; border: 1px solid #dcdfe6; border-radius: 4px;">
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button @click="showCreatePlugin = false" class="btn btn-default">取消</button>
|
||
<button @click="createPlugin" class="btn btn-primary" :disabled="creatingPlugin">
|
||
{{ creatingPlugin ? '创建中...' : '创建项目' }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/vue@3.3.8/dist/vue.global.js"></script>
|
||
<script>
|
||
const { createApp } = Vue;
|
||
|
||
createApp({
|
||
data() {
|
||
return {
|
||
uploading: false,
|
||
uploadProgress: 0,
|
||
selectedFile: null,
|
||
currentPlugin: 'cocos-ecs-extension', // 当前选中的插件
|
||
showCreatePlugin: false,
|
||
creatingPlugin: false,
|
||
newPlugin: {
|
||
id: '',
|
||
name: '',
|
||
displayName: '',
|
||
description: '',
|
||
author: '',
|
||
repository: '',
|
||
icon: '📦'
|
||
},
|
||
plugins: [],
|
||
versionInfo: {
|
||
pluginId: 'cocos-ecs-extension',
|
||
version: '',
|
||
channel: 'stable',
|
||
description: '',
|
||
mandatory: false
|
||
},
|
||
stats: {
|
||
totalVersions: 0,
|
||
activeUsers: 0,
|
||
todayUpdates: 0,
|
||
successRate: 100.0
|
||
},
|
||
versions: []
|
||
}
|
||
},
|
||
computed: {
|
||
filteredVersions() {
|
||
if (!this.currentPlugin) {
|
||
return this.versions;
|
||
}
|
||
return this.versions.filter(v => v.pluginId === this.currentPlugin);
|
||
}
|
||
},
|
||
methods: {
|
||
selectPlugin(pluginId) {
|
||
this.currentPlugin = pluginId;
|
||
this.versionInfo.pluginId = pluginId;
|
||
},
|
||
filterVersions() {
|
||
// 触发计算属性重新计算
|
||
},
|
||
getCurrentPluginName() {
|
||
if (!this.currentPlugin) return '全部插件';
|
||
const plugin = this.plugins.find(p => p.id === this.currentPlugin);
|
||
return plugin ? plugin.displayName : '未知插件';
|
||
},
|
||
getPluginIcon(pluginId) {
|
||
const plugin = this.plugins.find(p => p.id === pluginId);
|
||
return plugin ? plugin.icon : '📦';
|
||
},
|
||
getPluginDisplayName(pluginId) {
|
||
const plugin = this.plugins.find(p => p.id === pluginId);
|
||
return plugin ? plugin.displayName : pluginId;
|
||
},
|
||
selectFile() {
|
||
this.$refs.fileInput.click();
|
||
},
|
||
handleFileSelect(event) {
|
||
const file = event.target.files[0];
|
||
if (file) {
|
||
this.selectedFile = file;
|
||
// 自动提取版本号(如果文件名包含版本信息)
|
||
const match = file.name.match(/(\d+\.\d+\.\d+)/);
|
||
if (match) {
|
||
this.versionInfo.version = match[1];
|
||
}
|
||
}
|
||
},
|
||
async uploadVersion() {
|
||
if (!this.selectedFile) return;
|
||
|
||
this.uploading = true;
|
||
this.uploadProgress = 0;
|
||
|
||
try {
|
||
const formData = new FormData();
|
||
formData.append('package', this.selectedFile);
|
||
formData.append('pluginId', this.versionInfo.pluginId);
|
||
formData.append('version', this.versionInfo.version);
|
||
formData.append('channel', this.versionInfo.channel);
|
||
formData.append('description', this.versionInfo.description);
|
||
formData.append('mandatory', this.versionInfo.mandatory.toString());
|
||
|
||
// 模拟上传进度
|
||
const progressInterval = setInterval(() => {
|
||
this.uploadProgress = Math.min(this.uploadProgress + Math.random() * 15, 90);
|
||
}, 200);
|
||
|
||
// 调用真实的上传API
|
||
const response = await fetch('/api/upload/package', {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
|
||
clearInterval(progressInterval);
|
||
this.uploadProgress = 100;
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
alert(`版本上传成功!\n插件: ${result.data.pluginId}\n版本: ${result.data.version}\n文件数: ${result.data.filesCount}`);
|
||
|
||
// 重置表单
|
||
this.selectedFile = null;
|
||
this.versionInfo = {
|
||
pluginId: this.currentPlugin,
|
||
version: '',
|
||
channel: 'stable',
|
||
description: '',
|
||
mandatory: false
|
||
};
|
||
this.$refs.fileInput.value = '';
|
||
|
||
// 刷新数据
|
||
await this.refreshVersions();
|
||
await this.refreshStats();
|
||
} else {
|
||
alert('上传失败: ' + result.error);
|
||
}
|
||
|
||
} catch (error) {
|
||
alert('上传失败: ' + error.message);
|
||
} finally {
|
||
this.uploading = false;
|
||
}
|
||
},
|
||
async refreshVersions() {
|
||
try {
|
||
const params = new URLSearchParams();
|
||
if (this.currentPlugin) {
|
||
params.set('pluginId', this.currentPlugin);
|
||
}
|
||
|
||
const response = await fetch(`/api/versions?${params}`);
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
this.versions = result.data.map(v => ({
|
||
id: v.id,
|
||
pluginId: v.pluginId,
|
||
version: v.version,
|
||
channel: v.channel,
|
||
description: v.description,
|
||
release_date: v.releaseDate,
|
||
file_size: v.fileSize,
|
||
status: v.status
|
||
}));
|
||
} else {
|
||
console.error('获取版本列表失败:', result.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('刷新版本列表失败:', error);
|
||
}
|
||
},
|
||
async refreshStats() {
|
||
try {
|
||
const response = await fetch('/api/stats');
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
this.stats = result.data;
|
||
} else {
|
||
console.error('获取统计数据失败:', result.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('刷新统计数据失败:', error);
|
||
}
|
||
},
|
||
editVersion(version) {
|
||
// 编辑版本
|
||
console.log('编辑版本:', version);
|
||
},
|
||
deleteVersion(version) {
|
||
if (confirm('确定要删除版本 ' + version.version + ' 吗?')) {
|
||
// 删除版本
|
||
console.log('删除版本:', version);
|
||
}
|
||
},
|
||
getChannelName(channel) {
|
||
const names = { stable: '稳定版', beta: '测试版', dev: '开发版' };
|
||
return names[channel] || channel;
|
||
},
|
||
getStatusName(status) {
|
||
const names = { active: '已发布', draft: '草稿' };
|
||
return names[status] || status;
|
||
},
|
||
formatDate(dateString) {
|
||
return new Date(dateString).toLocaleString('zh-CN');
|
||
},
|
||
formatSize(bytes) {
|
||
const units = ['B', 'KB', 'MB', 'GB'];
|
||
let size = bytes;
|
||
let unitIndex = 0;
|
||
while (size >= 1024 && unitIndex < units.length - 1) {
|
||
size /= 1024;
|
||
unitIndex++;
|
||
}
|
||
return size.toFixed(1) + ' ' + units[unitIndex];
|
||
}
|
||
},
|
||
async mounted() {
|
||
// 加载插件列表
|
||
await this.loadPlugins();
|
||
|
||
// 加载初始数据
|
||
await this.refreshStats();
|
||
await this.refreshVersions();
|
||
},
|
||
async loadPlugins() {
|
||
try {
|
||
const response = await fetch('/api/plugins');
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
this.plugins = result.data.map(p => ({
|
||
id: p.id,
|
||
name: p.name,
|
||
displayName: p.displayName,
|
||
description: p.description,
|
||
author: p.author,
|
||
repository: p.repository,
|
||
icon: p.icon,
|
||
status: p.status,
|
||
versionCount: p.versionCount || 0,
|
||
totalDownloads: p.totalDownloads || 0
|
||
}));
|
||
|
||
// 如果没有选中插件且有插件数据,自动选中第一个
|
||
if (!this.currentPlugin && this.plugins.length > 0) {
|
||
this.currentPlugin = this.plugins[0].id;
|
||
this.versionInfo.pluginId = this.plugins[0].id;
|
||
}
|
||
} else {
|
||
console.error('获取插件列表失败:', result.error);
|
||
}
|
||
} catch (error) {
|
||
console.error('加载插件列表失败:', error);
|
||
}
|
||
},
|
||
async createPlugin() {
|
||
if (!this.newPlugin.id || !this.newPlugin.name || !this.newPlugin.displayName) {
|
||
alert('请填写必要的字段:项目ID、项目名称、显示名称');
|
||
return;
|
||
}
|
||
|
||
this.creatingPlugin = true;
|
||
|
||
try {
|
||
const response = await fetch('/api/plugins', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(this.newPlugin)
|
||
});
|
||
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
alert(`项目创建成功!\n项目名称: ${result.data.displayName}\n项目ID: ${result.data.id}`);
|
||
|
||
// 重置表单
|
||
this.newPlugin = {
|
||
id: '',
|
||
name: '',
|
||
displayName: '',
|
||
description: '',
|
||
author: '',
|
||
repository: '',
|
||
icon: '📦'
|
||
};
|
||
|
||
// 关闭模态框
|
||
this.showCreatePlugin = false;
|
||
|
||
// 刷新插件列表
|
||
await this.loadPlugins();
|
||
await this.refreshStats();
|
||
} else {
|
||
alert('创建失败: ' + result.error);
|
||
}
|
||
|
||
} catch (error) {
|
||
alert('创建失败: ' + error.message);
|
||
} finally {
|
||
this.creatingPlugin = false;
|
||
}
|
||
}
|
||
}).mount('#app');
|
||
</script>
|
||
</body>
|
||
</html> |