264 lines
15 KiB
HTML
264 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<title>GoHttp 管理控制台</title>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.15.13/theme-chalk/index.min.css">
|
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
|
<link rel="stylesheet" href="css/style.css">
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<div class="container mx-auto px-4 py-8">
|
|
<!-- Header -->
|
|
<el-header class="flex justify-between items-center mb-8">
|
|
<div class="flex items-center">
|
|
<i class="fas fa-server text-3xl mr-3 text-blue-400"></i>
|
|
<h1 class="text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-purple-500">
|
|
GoHttp 管理控制台
|
|
</h1>
|
|
</div>
|
|
<div class="flex items-center space-x-4">
|
|
<el-button type="primary" @click="refreshAll" :loading="loading">
|
|
<i class="fas fa-sync mr-2"></i>刷新
|
|
</el-button>
|
|
</div>
|
|
</el-header>
|
|
|
|
<!-- Tabs -->
|
|
<el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
|
<!-- 服务器配置 -->
|
|
<el-tab-pane label="服务器配置" name="servers">
|
|
<el-card class="glass-card mb-6">
|
|
<div slot="header" class="flex justify-between items-center">
|
|
<span class="text-xl font-semibold text-blue-300">
|
|
<i class="fas fa-cog mr-2"></i>HTTP服务器
|
|
</span>
|
|
<el-button type="primary" @click="showServerDialog()" size="small">
|
|
<i class="fas fa-plus mr-1"></i>添加服务器
|
|
</el-button>
|
|
</div>
|
|
|
|
<el-table :data="servers" stripe style="width: 100%" v-loading="loading">
|
|
<el-table-column prop="name" label="名称" width="150"></el-table-column>
|
|
<el-table-column prop="server" label="域名" width="200">
|
|
<template slot-scope="scope">
|
|
{{ scope.row.server ? scope.row.server.join(', ') : '-' }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column prop="port" label="端口" width="100"></el-table-column>
|
|
<el-table-column label="SSL" width="80">
|
|
<template slot-scope="scope">
|
|
<el-tag :type="scope.row.enable_ssl ? 'success' : 'info'" size="small">
|
|
{{ scope.row.enable_ssl ? '启用' : '禁用' }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="路径数" width="80">
|
|
<template slot-scope="scope">
|
|
{{ scope.row.paths ? scope.row.paths.length : 0 }}
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" min-width="280">
|
|
<template slot-scope="scope">
|
|
<el-button type="text" size="small" @click="showServerDialog(scope.row)" class="mr-2">
|
|
<i class="fas fa-edit mr-1"></i>编辑
|
|
</el-button>
|
|
<el-button type="text" size="small" @click="restartServer(scope.row.name)" class="mr-2">
|
|
<i class="fas fa-redo mr-1"></i>重启
|
|
</el-button>
|
|
<el-button type="text" size="small" @click="deleteServer(scope.row.name)" class="text-red-400">
|
|
<i class="fas fa-trash mr-1"></i>删除
|
|
</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-card>
|
|
</el-tab-pane>
|
|
|
|
<!-- TCP代理 -->
|
|
<el-tab-pane label="TCP代理" name="tcp">
|
|
<el-card class="glass-card mb-6">
|
|
<div slot="header" class="flex justify-between items-center">
|
|
<span class="text-xl font-semibold text-blue-300">
|
|
<i class="fas fa-exchange-alt mr-2"></i>TCP代理
|
|
</span>
|
|
<el-button type="primary" @click="showTcpDialog()" size="small">
|
|
<i class="fas fa-plus mr-1"></i>添加代理
|
|
</el-button>
|
|
</div>
|
|
|
|
<el-table :data="tcpProxies" stripe style="width: 100%" v-loading="loading">
|
|
<el-table-column prop="name" label="名称" width="150"></el-table-column>
|
|
<el-table-column prop="listen" label="监听" width="200"></el-table-column>
|
|
<el-table-column prop="target" label="目标"></el-table-column>
|
|
<el-table-column label="状态" width="100">
|
|
<template slot-scope="scope">
|
|
<el-tag :type="isTcpRunning(scope.row.name) ? 'success' : 'info'" size="small">
|
|
{{ isTcpRunning(scope.row.name) ? '运行中' : '已停止' }}
|
|
</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="操作" min-width="200">
|
|
<template slot-scope="scope">
|
|
<el-button type="text" size="small" @click="showTcpDialog(scope.row)" class="mr-2">
|
|
<i class="fas fa-edit mr-1"></i>编辑
|
|
</el-button>
|
|
<el-button type="text" size="small" @click="toggleTcpProxy(scope.row)" class="mr-2">
|
|
<i :class="isTcpRunning(scope.row.name) ? 'fas fa-stop mr-1' : 'fas fa-play mr-1'"></i>
|
|
{{ isTcpRunning(scope.row.name) ? '停止' : '启动' }}
|
|
</el-button>
|
|
<el-button type="text" size="small" @click="deleteTcpProxy(scope.row.name)" class="text-red-400">
|
|
<i class="fas fa-trash mr-1"></i>删除
|
|
</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-card>
|
|
</el-tab-pane>
|
|
|
|
<!-- 系统状态 -->
|
|
<el-tab-pane label="系统状态" name="status">
|
|
<el-row :gutter="20">
|
|
<el-col :span="8">
|
|
<el-card class="glass-card text-center">
|
|
<div class="text-3xl font-bold text-green-400 mb-1">{{ goroutines }}</div>
|
|
<div class="text-xs text-gray-400">Goroutines</div>
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
</div>
|
|
|
|
<!-- Server Dialog -->
|
|
<el-dialog :title="serverDialog.title" :visible.sync="serverDialog.visible" width="70%" @closed="resetServerForm">
|
|
<el-form :model="serverDialog.form" label-width="120px" ref="serverForm">
|
|
<el-row :gutter="20">
|
|
<el-col :span="12">
|
|
<el-form-item label="名称" prop="name" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]">
|
|
<el-input v-model="serverDialog.form.name" :disabled="serverDialog.isEdit"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="端口" prop="port" :rules="[{ required: true, message: '请输入端口', trigger: 'blur' }]">
|
|
<el-input-number v-model="serverDialog.form.port" :min="1" :max="65535"></el-input-number>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-form-item label="域名" prop="server">
|
|
<el-select v-model="serverDialog.form.server" multiple filterable allow-create placeholder="输入域名后回车" style="width: 100%">
|
|
<el-option v-for="s in serverDialog.form.server" :key="s" :label="s" :value="s"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
|
|
<el-row :gutter="20">
|
|
<el-col :span="12">
|
|
<el-form-item label="启用SSL">
|
|
<el-switch v-model="serverDialog.form.enable_ssl"></el-switch>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12" v-if="serverDialog.form.enable_ssl">
|
|
<el-form-item label="证书文件">
|
|
<el-input v-model="serverDialog.form.certfile" placeholder="/path/to/cert.pem"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-row :gutter="20" v-if="serverDialog.form.enable_ssl">
|
|
<el-col :span="12">
|
|
<el-form-item label="密钥文件">
|
|
<el-input v-model="serverDialog.form.keyfile" placeholder="/path/to/key.pem"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<!-- Paths -->
|
|
<el-divider><i class="fas fa-route mr-2"></i>路由配置</el-divider>
|
|
|
|
<div v-for="(path, index) in serverDialog.form.paths" :key="index" class="glass-card p-4 mb-4">
|
|
<el-row :gutter="20">
|
|
<el-col :span="8">
|
|
<el-form-item label="路径">
|
|
<el-input v-model="path.path" placeholder="/api"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="8">
|
|
<el-form-item label="类型">
|
|
<el-select v-model="path.type" @change="onPathTypeChange(path)">
|
|
<el-option label="静态文件" value="static"></el-option>
|
|
<el-option label="反向代理" value="proxy"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="8">
|
|
<el-form-item label="操作">
|
|
<el-button type="danger" icon="el-icon-delete" circle @click="removePath(index)"></el-button>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-row :gutter="20" v-if="path.type === 'static'">
|
|
<el-col :span="12">
|
|
<el-form-item label="根目录">
|
|
<el-input v-model="path.root" placeholder="/var/www/html"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
<el-col :span="12">
|
|
<el-form-item label="默认文件">
|
|
<el-input v-model="path.default" placeholder="index.html"></el-input>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
|
|
<el-row :gutter="20" v-if="path.type === 'proxy'">
|
|
<el-col :span="24">
|
|
<el-form-item label="上游服务器">
|
|
<el-select v-model="path.upstreams" multiple filterable allow-create placeholder="输入地址后回车" style="width: 100%">
|
|
<el-option v-for="u in path.upstreams" :key="u" :label="u" :value="u"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
</el-col>
|
|
</el-row>
|
|
</div>
|
|
|
|
<el-button type="primary" plain @click="addPath" class="mb-4">
|
|
<i class="fas fa-plus mr-1"></i>添加路由
|
|
</el-button>
|
|
</el-form>
|
|
|
|
<span slot="footer" class="dialog-footer">
|
|
<el-button @click="serverDialog.visible = false">取消</el-button>
|
|
<el-button type="primary" @click="saveServer" :loading="serverDialog.saving">保存</el-button>
|
|
</span>
|
|
</el-dialog>
|
|
|
|
<!-- TCP Proxy Dialog -->
|
|
<el-dialog :title="tcpDialog.title" :visible.sync="tcpDialog.visible" width="500px" @closed="resetTcpForm">
|
|
<el-form :model="tcpDialog.form" label-width="100px" ref="tcpForm">
|
|
<el-form-item label="名称" prop="name" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]">
|
|
<el-input v-model="tcpDialog.form.name" :disabled="tcpDialog.isEdit"></el-input>
|
|
</el-form-item>
|
|
<el-form-item label="监听地址" prop="listen" :rules="[{ required: true, message: '请输入监听地址', trigger: 'blur' }]">
|
|
<el-input v-model="tcpDialog.form.listen" placeholder="0.0.0.0:3306"></el-input>
|
|
</el-form-item>
|
|
<el-form-item label="目标地址" prop="target" :rules="[{ required: true, message: '请输入目标地址', trigger: 'blur' }]">
|
|
<el-input v-model="tcpDialog.form.target" placeholder="192.168.1.100:3306"></el-input>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<span slot="footer" class="dialog-footer">
|
|
<el-button @click="tcpDialog.visible = false">取消</el-button>
|
|
<el-button type="primary" @click="saveTcpProxy" :loading="tcpDialog.saving">保存</el-button>
|
|
</span>
|
|
</el-dialog>
|
|
</div>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.15.13/index.min.js"></script>
|
|
<script src="js/app.js"></script>
|
|
</body>
|
|
</html> |