This commit is contained in:
Flik
2025-12-27 22:49:07 +08:00
parent 622f30b381
commit 4b71ff1604
10 changed files with 351 additions and 87 deletions

View File

@@ -3,7 +3,7 @@ import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import {
NCard, NButton, NSpace, NTag, NTable, NEmpty,
NFormItem, NInput, NInputNumber, NSelect, NModal, NCheckbox,
NFormItem, NInput, NInputNumber, NSelect, NModal, NCheckbox, NSwitch,
NIcon, useMessage, useDialog
} from 'naive-ui'
import {
@@ -12,7 +12,7 @@ import {
DownloadOutline
} from '@vicons/ionicons5'
import { getClient, updateClient, deleteClient, pushConfigToClient, disconnectClient, getPlugins, installPluginsToClient } from '../api'
import type { ProxyRule, PluginInfo } from '../types'
import type { ProxyRule, PluginInfo, ClientPlugin } from '../types'
const route = useRoute()
const router = useRouter()
@@ -24,6 +24,7 @@ const online = ref(false)
const lastPing = ref('')
const nickname = ref('')
const rules = ref<ProxyRule[]>([])
const clientPlugins = ref<ClientPlugin[]>([])
const editing = ref(false)
const editNickname = ref('')
const editRules = ref<ProxyRule[]>([])
@@ -68,6 +69,7 @@ const loadClient = async () => {
lastPing.value = data.last_ping || ''
nickname.value = data.nickname || ''
rules.value = data.rules || []
clientPlugins.value = data.plugins || []
} catch (e) {
console.error('Failed to load client', e)
}
@@ -79,7 +81,8 @@ const startEdit = () => {
editNickname.value = nickname.value
editRules.value = rules.value.map(rule => ({
...rule,
type: rule.type || 'tcp'
type: rule.type || 'tcp',
enabled: rule.enabled !== false
}))
editing.value = true
}
@@ -90,7 +93,7 @@ const cancelEdit = () => {
const addRule = () => {
editRules.value.push({
name: '', local_ip: '127.0.0.1', local_port: 80, remote_port: 8080, type: 'tcp'
name: '', local_ip: '127.0.0.1', local_port: 80, remote_port: 8080, type: 'tcp', enabled: true
})
}
@@ -167,6 +170,25 @@ const installPlugins = async () => {
message.error(e.response?.data || '安装失败')
}
}
const toggleClientPlugin = async (plugin: ClientPlugin) => {
const newEnabled = !plugin.enabled
const updatedPlugins = clientPlugins.value.map(p =>
p.name === plugin.name ? { ...p, enabled: newEnabled } : p
)
try {
await updateClient(clientId, {
id: clientId,
nickname: nickname.value,
rules: rules.value,
plugins: updatedPlugins
})
plugin.enabled = newEnabled
message.success(newEnabled ? `已启用 ${plugin.name}` : `已禁用 ${plugin.name}`)
} catch (e) {
message.error('操作失败')
}
}
</script>
<template>
@@ -242,6 +264,7 @@ const installPlugins = async () => {
<th>本地地址</th>
<th>远程端口</th>
<th>类型</th>
<th>状态</th>
</tr>
</thead>
<tbody>
@@ -250,6 +273,11 @@ const installPlugins = async () => {
<td>{{ rule.local_ip }}:{{ rule.local_port }}</td>
<td>{{ rule.remote_port }}</td>
<td><n-tag size="small">{{ rule.type || 'tcp' }}</n-tag></td>
<td>
<n-tag size="small" :type="rule.enabled !== false ? 'success' : 'default'">
{{ rule.enabled !== false ? '启用' : '禁用' }}
</n-tag>
</td>
</tr>
</tbody>
</n-table>
@@ -263,6 +291,9 @@ const installPlugins = async () => {
</n-form-item>
<n-card v-for="(rule, i) in editRules" :key="i" size="small">
<n-space align="center">
<n-form-item label="启用" :show-feedback="false">
<n-switch v-model:value="rule.enabled" />
</n-form-item>
<n-form-item label="名称" :show-feedback="false">
<n-input v-model:value="rule.name" placeholder="规则名称" />
</n-form-item>
@@ -291,6 +322,29 @@ const installPlugins = async () => {
</template>
</n-card>
<!-- 已安装插件卡片 -->
<n-card title="已安装扩展" style="margin-top: 16px;">
<n-empty v-if="clientPlugins.length === 0" description="暂无已安装扩展" />
<n-table v-else :bordered="false" :single-line="false">
<thead>
<tr>
<th>名称</th>
<th>版本</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr v-for="plugin in clientPlugins" :key="plugin.name">
<td>{{ plugin.name }}</td>
<td>v{{ plugin.version }}</td>
<td>
<n-switch :value="plugin.enabled" @update:value="toggleClientPlugin(plugin)" />
</td>
</tr>
</tbody>
</n-table>
</n-card>
<!-- 安装插件模态框 -->
<n-modal v-model:show="showInstallModal" preset="card" title="安装插件到客户端" style="width: 500px;">
<n-empty v-if="availablePlugins.length === 0" description="暂无可用插件" />