feat: 新增 GRE 隧道协议,管理端口调整为 18080

- backend: 新增 GRE 隧道实现(ip tunnel 点对点互联),binmgr 支持 iproute2
- backend: api/identity 调整,各协议 service(gre/ikev2/ipsec/l2tp/openvpn)统一改动
- backend: OpenVPN 认证辅助与用户口令同步逻辑完善
- frontend: 协议图标/向导/编辑器支持 GRE,VPN 用户页重构(234 行)
- frontend: 新增 RouteListInput 路由列表输入组件,Dashboard/Layout 优化
- i18n: 中英文文案同步更新
- test: 新增 binmgr/common/gre 单测,openvpn 测试补充
- docs: README 补充 GRE 说明,默认监听端口 8080 → 18080
- chore: .gitignore 增加 opsx-vpn.previous(构建备份二进制)
This commit is contained in:
opsx committed 2026-10-20 20:58:58 +08:00
1 parent c7f59f2cbf
commit ef7eb378d2
28 files changed
+1363 -439

No files matched your search

+10 -9
View File
@@ -13,7 +13,12 @@
<el-option :label="$t('tunnels.stateError')" value="error" />
</el-select>
</div>
<el-button type="primary" :icon="Plus" @click="$router.push('/tunnels/create')">{{ $t('tunnels.createTunnel') }}</el-button>
<div style="display:flex;align-items:center;gap:8px">
<el-tooltip :content="$t('common.refresh')" placement="top">
<el-button :icon="Refresh" circle :loading="loading" @click="load" />
</el-tooltip>
<el-button type="primary" :icon="Plus" @click="$router.push('/tunnels/create')">{{ $t('tunnels.createTunnel') }}</el-button>
</div>
</div>
</template>
@@ -43,9 +48,7 @@
</el-table-column>
<el-table-column :label="$t('common.status')" width="110">
<template #default="{ row }">
<el-badge is-dot :type="dotType(row)" style="padding-left:12px">
<span :style="{ color: stateColor(row) }">{{ stateText(row) }}</span>
</el-badge>
<span :style="{ color: stateColor(row) }">{{ stateText(row) }}</span>
<el-tooltip v-if="row.runtime?.detail" :content="row.runtime.detail" placement="top">
<el-icon style="margin-left:4px;color:#909399;cursor:help"><InfoFilled /></el-icon>
</el-tooltip>
@@ -225,7 +228,7 @@
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useI18n } from 'vue-i18n'
import { Plus, InfoFilled, ArrowDown } from '@element-plus/icons-vue'
import { Plus, InfoFilled, ArrowDown, Refresh } from '@element-plus/icons-vue'
import QRCode from 'qrcode'
import { useRouter } from 'vue-router'
import api from '../api'
@@ -297,9 +300,6 @@ function stateText(row) {
function stateColor(row) {
return { running: '#67c23a', stopped: '#909399', error: '#f56c6c', undeployed: '#e6a23c' }[stateOf(row)]
}
function dotType(row) {
return { running: 'success', stopped: 'info', error: 'danger', undeployed: 'warning' }[stateOf(row)] || 'info'
}
function stateOf(row) { return row.runtime?.state || row.state }
function prettyConfig(c) {
try { return JSON.stringify(JSON.parse(c), null, 2) } catch { return c }
@@ -565,7 +565,8 @@ function download(row) {
const a = document.createElement('a')
const url = URL.createObjectURL(b)
a.href = url
a.download = `${row.protocol}-${row.name}.conf`
const ext = row.protocol === 'openvpn' ? 'ovpn' : 'conf'
a.download = `${row.protocol}-${row.name}.${ext}`
a.click()
URL.revokeObjectURL(url)
})