Remove plugin store config from server settings
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 28s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 1m24s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 1m33s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 1m17s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 1m54s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 1m40s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 1m8s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 1m46s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m57s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 1m9s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 1m50s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 1m24s
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 28s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 1m24s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 1m33s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 1m17s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 1m54s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 1m40s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 1m8s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 1m46s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m57s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 1m9s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 1m50s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 1m24s
This commit is contained in:
@@ -1,15 +1,12 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
// UpdateServerConfigRequest 更新服务器配置请求
|
// UpdateServerConfigRequest is the config update payload.
|
||||||
// @Description 更新服务器配置
|
|
||||||
type UpdateServerConfigRequest struct {
|
type UpdateServerConfigRequest struct {
|
||||||
Server *ServerConfigPart `json:"server"`
|
Server *ServerConfigPart `json:"server"`
|
||||||
Web *WebConfigPart `json:"web"`
|
Web *WebConfigPart `json:"web"`
|
||||||
PluginStore *PluginStoreConfigPart `json:"plugin_store"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfigPart 服务器配置部分
|
// ServerConfigPart is the server config subset.
|
||||||
// @Description 隧道服务器配置
|
|
||||||
type ServerConfigPart struct {
|
type ServerConfigPart struct {
|
||||||
BindAddr string `json:"bind_addr" binding:"omitempty"`
|
BindAddr string `json:"bind_addr" binding:"omitempty"`
|
||||||
BindPort int `json:"bind_port" binding:"omitempty,min=1,max=65535"`
|
BindPort int `json:"bind_port" binding:"omitempty,min=1,max=65535"`
|
||||||
@@ -18,8 +15,7 @@ type ServerConfigPart struct {
|
|||||||
HeartbeatTimeout int `json:"heartbeat_timeout" binding:"omitempty,min=1,max=600"`
|
HeartbeatTimeout int `json:"heartbeat_timeout" binding:"omitempty,min=1,max=600"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebConfigPart Web 配置部分
|
// WebConfigPart is the web console config subset.
|
||||||
// @Description Web 控制台配置
|
|
||||||
type WebConfigPart struct {
|
type WebConfigPart struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
BindPort int `json:"bind_port" binding:"omitempty,min=1,max=65535"`
|
BindPort int `json:"bind_port" binding:"omitempty,min=1,max=65535"`
|
||||||
@@ -27,37 +23,25 @@ type WebConfigPart struct {
|
|||||||
Password string `json:"password" binding:"omitempty,min=6,max=64"`
|
Password string `json:"password" binding:"omitempty,min=6,max=64"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfigResponse 服务器配置响应
|
// ServerConfigResponse is the config response payload.
|
||||||
// @Description 服务器配置信息
|
|
||||||
type ServerConfigResponse struct {
|
type ServerConfigResponse struct {
|
||||||
Server ServerConfigInfo `json:"server"`
|
Server ServerConfigInfo `json:"server"`
|
||||||
Web WebConfigInfo `json:"web"`
|
Web WebConfigInfo `json:"web"`
|
||||||
PluginStore PluginStoreConfigInfo `json:"plugin_store"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfigInfo 服务器配置信息
|
// ServerConfigInfo describes the server config.
|
||||||
type ServerConfigInfo struct {
|
type ServerConfigInfo struct {
|
||||||
BindAddr string `json:"bind_addr"`
|
BindAddr string `json:"bind_addr"`
|
||||||
BindPort int `json:"bind_port"`
|
BindPort int `json:"bind_port"`
|
||||||
Token string `json:"token"` // 脱敏后的 token
|
Token string `json:"token"`
|
||||||
HeartbeatSec int `json:"heartbeat_sec"`
|
HeartbeatSec int `json:"heartbeat_sec"`
|
||||||
HeartbeatTimeout int `json:"heartbeat_timeout"`
|
HeartbeatTimeout int `json:"heartbeat_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebConfigInfo Web 配置信息
|
// WebConfigInfo describes the web console config.
|
||||||
type WebConfigInfo struct {
|
type WebConfigInfo struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
BindPort int `json:"bind_port"`
|
BindPort int `json:"bind_port"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"` // 显示为 ****
|
Password string `json:"password"`
|
||||||
}
|
|
||||||
|
|
||||||
// PluginStoreConfigPart 插件商店配置部分
|
|
||||||
type PluginStoreConfigPart struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PluginStoreConfigInfo 插件商店配置信息
|
|
||||||
type PluginStoreConfigInfo struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,20 +162,14 @@ export interface WebConfigInfo {
|
|||||||
password: string
|
password: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PluginStoreConfigInfo {
|
|
||||||
url: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ServerConfigResponse {
|
export interface ServerConfigResponse {
|
||||||
server: ServerConfigInfo
|
server: ServerConfigInfo
|
||||||
web: WebConfigInfo
|
web: WebConfigInfo
|
||||||
plugin_store: PluginStoreConfigInfo
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateServerConfigRequest {
|
export interface UpdateServerConfigRequest {
|
||||||
server?: Partial<ServerConfigInfo>
|
server?: Partial<ServerConfigInfo>
|
||||||
web?: Partial<WebConfigInfo>
|
web?: Partial<WebConfigInfo>
|
||||||
plugin_store?: Partial<PluginStoreConfigInfo>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getServerConfig = () => get<ServerConfigResponse>('/config')
|
export const getServerConfig = () => get<ServerConfigResponse>('/config')
|
||||||
|
|||||||
@@ -1,37 +1,38 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
import { ServerOutline, SettingsOutline, SaveOutline } from '@vicons/ionicons5'
|
import { SaveOutline, ServerOutline, SettingsOutline } from '@vicons/ionicons5'
|
||||||
import { useToast } from '../composables/useToast'
|
|
||||||
import {
|
import {
|
||||||
getVersionInfo, getServerConfig, updateServerConfig,
|
getServerConfig,
|
||||||
type VersionInfo, type ServerConfigResponse
|
getVersionInfo,
|
||||||
|
updateServerConfig,
|
||||||
|
type ServerConfigResponse,
|
||||||
|
type UpdateServerConfigRequest,
|
||||||
|
type VersionInfo,
|
||||||
} from '../api'
|
} from '../api'
|
||||||
|
import { useToast } from '../composables/useToast'
|
||||||
|
|
||||||
const message = useToast()
|
const message = useToast()
|
||||||
|
|
||||||
const versionInfo = ref<VersionInfo | null>(null)
|
const versionInfo = ref<VersionInfo | null>(null)
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
|
|
||||||
// 服务器配置
|
|
||||||
const serverConfig = ref<ServerConfigResponse | null>(null)
|
const serverConfig = ref<ServerConfigResponse | null>(null)
|
||||||
const configLoading = ref(false)
|
const configLoading = ref(false)
|
||||||
const savingConfig = ref(false)
|
const savingConfig = ref(false)
|
||||||
|
|
||||||
// 配置表单
|
|
||||||
const configForm = ref({
|
const configForm = ref({
|
||||||
heartbeat_sec: 30,
|
heartbeat_sec: 30,
|
||||||
heartbeat_timeout: 90,
|
heartbeat_timeout: 90,
|
||||||
web_username: '',
|
web_username: '',
|
||||||
web_password: '',
|
web_password: '',
|
||||||
plugin_store_url: ''
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const loadVersionInfo = async () => {
|
const loadVersionInfo = async () => {
|
||||||
try {
|
try {
|
||||||
const { data } = await getVersionInfo()
|
const { data } = await getVersionInfo()
|
||||||
versionInfo.value = data
|
versionInfo.value = data
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
console.error('Failed to load version info', e)
|
console.error('Failed to load version info', error)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
@@ -42,16 +43,14 @@ const loadServerConfig = async () => {
|
|||||||
try {
|
try {
|
||||||
const { data } = await getServerConfig()
|
const { data } = await getServerConfig()
|
||||||
serverConfig.value = data
|
serverConfig.value = data
|
||||||
// 填充表单
|
|
||||||
configForm.value = {
|
configForm.value = {
|
||||||
heartbeat_sec: data.server.heartbeat_sec,
|
heartbeat_sec: data.server.heartbeat_sec,
|
||||||
heartbeat_timeout: data.server.heartbeat_timeout,
|
heartbeat_timeout: data.server.heartbeat_timeout,
|
||||||
web_username: data.web.username,
|
web_username: data.web.username,
|
||||||
web_password: '',
|
web_password: '',
|
||||||
plugin_store_url: data.plugin_store.url
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
console.error('Failed to load server config', e)
|
console.error('Failed to load server config', error)
|
||||||
} finally {
|
} finally {
|
||||||
configLoading.value = false
|
configLoading.value = false
|
||||||
}
|
}
|
||||||
@@ -60,27 +59,28 @@ const loadServerConfig = async () => {
|
|||||||
const handleSaveConfig = async () => {
|
const handleSaveConfig = async () => {
|
||||||
savingConfig.value = true
|
savingConfig.value = true
|
||||||
try {
|
try {
|
||||||
const updateReq: any = {
|
const updateReq: UpdateServerConfigRequest = {
|
||||||
server: {
|
server: {
|
||||||
heartbeat_sec: configForm.value.heartbeat_sec,
|
heartbeat_sec: configForm.value.heartbeat_sec,
|
||||||
heartbeat_timeout: configForm.value.heartbeat_timeout
|
heartbeat_timeout: configForm.value.heartbeat_timeout,
|
||||||
},
|
},
|
||||||
web: {
|
web: {
|
||||||
username: configForm.value.web_username
|
username: configForm.value.web_username,
|
||||||
},
|
},
|
||||||
plugin_store: {
|
|
||||||
url: configForm.value.plugin_store_url
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// 只有填写了密码才更新
|
|
||||||
if (configForm.value.web_password) {
|
if (configForm.value.web_password) {
|
||||||
updateReq.web.password = configForm.value.web_password
|
updateReq.web = {
|
||||||
|
...updateReq.web,
|
||||||
|
password: configForm.value.web_password,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await updateServerConfig(updateReq)
|
await updateServerConfig(updateReq)
|
||||||
message.success('配置已保存,部分配置需要重启服务后生效')
|
message.success('配置已保存,部分配置需要重启服务后生效')
|
||||||
configForm.value.web_password = ''
|
configForm.value.web_password = ''
|
||||||
} catch (e: any) {
|
} catch (error: any) {
|
||||||
message.error(e.response?.data || '保存配置失败')
|
message.error(error.response?.data || '保存配置失败')
|
||||||
} finally {
|
} finally {
|
||||||
savingConfig.value = false
|
savingConfig.value = false
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,6 @@ onMounted(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="settings-page">
|
<div class="settings-page">
|
||||||
<!-- Particles -->
|
|
||||||
<div class="particles">
|
<div class="particles">
|
||||||
<div class="particle particle-1"></div>
|
<div class="particle particle-1"></div>
|
||||||
<div class="particle particle-2"></div>
|
<div class="particle particle-2"></div>
|
||||||
@@ -102,13 +101,11 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settings-content">
|
<div class="settings-content">
|
||||||
<!-- Header -->
|
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1 class="page-title">系统设置</h1>
|
<h1 class="page-title">系统设置</h1>
|
||||||
<p class="page-subtitle">管理服务端配置和系统更新</p>
|
<p class="page-subtitle">管理服务端配置和系统更新</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Version Info Card -->
|
|
||||||
<div class="glass-card">
|
<div class="glass-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3>版本信息</h3>
|
<h3>版本信息</h3>
|
||||||
@@ -146,7 +143,6 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Server Config Card -->
|
|
||||||
<div class="glass-card">
|
<div class="glass-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h3>服务器配置</h3>
|
<h3>服务器配置</h3>
|
||||||
@@ -201,19 +197,6 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-divider"></div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">插件商店地址</label>
|
|
||||||
<input
|
|
||||||
v-model="configForm.plugin_store_url"
|
|
||||||
type="text"
|
|
||||||
class="glass-input"
|
|
||||||
placeholder="https://git.92coco.cn/flik/GoTunnel-Plugins/raw/branch/main/store.json"
|
|
||||||
/>
|
|
||||||
<span class="form-hint">插件商店的 API 地址,留空使用默认地址</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button
|
<button
|
||||||
class="glass-btn primary"
|
class="glass-btn primary"
|
||||||
@@ -241,7 +224,6 @@ onMounted(() => {
|
|||||||
padding: 32px;
|
padding: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hide particles */
|
|
||||||
.particles {
|
.particles {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@@ -315,7 +297,6 @@ onMounted(() => {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Glass Card */
|
|
||||||
.glass-card {
|
.glass-card {
|
||||||
background: var(--color-bg-tertiary);
|
background: var(--color-bg-tertiary);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
@@ -342,7 +323,6 @@ onMounted(() => {
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Info Grid */
|
|
||||||
.info-grid {
|
.info-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
@@ -350,7 +330,9 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
.info-grid { grid-template-columns: repeat(2, 1fr); }
|
.info-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-item {
|
.info-item {
|
||||||
@@ -374,65 +356,13 @@ onMounted(() => {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* States */
|
.loading-state,
|
||||||
.loading-state, .empty-state {
|
.empty-state {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
color: var(--color-text-muted);
|
color: var(--color-text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update Alert */
|
|
||||||
.update-alert {
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.update-alert.success {
|
|
||||||
background: rgba(0, 186, 124, 0.15);
|
|
||||||
border: 1px solid rgba(0, 186, 124, 0.3);
|
|
||||||
color: var(--color-success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.update-alert.info {
|
|
||||||
background: rgba(29, 155, 240, 0.15);
|
|
||||||
border: 1px solid rgba(29, 155, 240, 0.3);
|
|
||||||
color: var(--color-info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Download Info */
|
|
||||||
.download-info {
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
font-size: 13px;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release Note */
|
|
||||||
.release-note {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-label {
|
|
||||||
display: block;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.release-note pre {
|
|
||||||
margin: 0;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
background: var(--color-bg-elevated);
|
|
||||||
padding: 12px;
|
|
||||||
border-radius: 8px;
|
|
||||||
max-height: 150px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Glass Button */
|
|
||||||
.glass-btn {
|
.glass-btn {
|
||||||
background: var(--color-bg-elevated);
|
background: var(--color-bg-elevated);
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
@@ -456,11 +386,6 @@ onMounted(() => {
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
.glass-btn.small {
|
|
||||||
padding: 6px 12px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.glass-btn.primary {
|
.glass-btn.primary {
|
||||||
background: var(--color-accent);
|
background: var(--color-accent);
|
||||||
border: none;
|
border: none;
|
||||||
@@ -470,7 +395,6 @@ onMounted(() => {
|
|||||||
background: var(--color-accent-hover);
|
background: var(--color-accent-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Icon styles */
|
|
||||||
.header-icon {
|
.header-icon {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@@ -482,7 +406,6 @@ onMounted(() => {
|
|||||||
height: 14px;
|
height: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Config Form */
|
|
||||||
.config-form {
|
.config-form {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -501,11 +424,6 @@ onMounted(() => {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-hint {
|
|
||||||
font-size: 11px;
|
|
||||||
color: var(--color-text-muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-row {
|
.form-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
@@ -528,7 +446,6 @@ onMounted(() => {
|
|||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Glass Input */
|
|
||||||
.glass-input {
|
.glass-input {
|
||||||
background: var(--color-bg-elevated);
|
background: var(--color-bg-elevated);
|
||||||
border: 1px solid var(--color-border);
|
border: 1px solid var(--color-border);
|
||||||
|
|||||||
Reference in New Issue
Block a user