117 lines
4.4 KiB
Vue
117 lines
4.4 KiB
Vue
<template>
|
|
<div>
|
|
<h2 class="text-xl font-bold mb-5">设置</h2>
|
|
|
|
<div v-if="loading" class="text-gray-400 text-sm">加载中...</div>
|
|
<div v-else class="space-y-4">
|
|
<!-- General settings -->
|
|
<div class="bg-white rounded-lg p-4 shadow-sm border">
|
|
<h3 class="font-semibold mb-3 text-sm">通用</h3>
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-sm mb-1">默认 User-Agent</label>
|
|
<input v-model="settings.defaultUserAgent" class="w-full px-3 py-2 border rounded-lg text-sm" />
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm mb-1">默认流量查询 User-Agent</label>
|
|
<input v-model="settings.defaultFlowUserAgent" class="w-full px-3 py-2 border rounded-lg text-sm" />
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm mb-1">请求超时 (ms)</label>
|
|
<input v-model="settings.defaultTimeout" class="w-full px-3 py-2 border rounded-lg text-sm" />
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm mb-1">后端并发数</label>
|
|
<input v-model="settings.backendRequestConcurrency" class="w-full px-3 py-2 border rounded-lg text-sm" />
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm mb-1">远程缓存 TTL (秒)</label>
|
|
<input v-model="settings.remoteCacheTtl" class="w-full px-3 py-2 border rounded-lg text-sm" />
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<input type="checkbox" id="cache-stale" v-model="settings.remoteCacheStaleOnError" class="rounded" />
|
|
<label for="cache-stale" class="text-sm">缓存过期时仍返回旧数据</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Node info API -->
|
|
<div class="bg-white rounded-lg p-4 shadow-sm border">
|
|
<h3 class="font-semibold mb-3 text-sm">节点信息 API</h3>
|
|
<input v-model="settings.nodeInfoApiUrl" placeholder="https://ipwho.is/{ip}"
|
|
class="w-full px-3 py-2 border rounded-lg text-sm font-mono" />
|
|
<p class="text-xs text-gray-400 mt-1">URL 中 {ip} 会被替换为查询的 IP</p>
|
|
</div>
|
|
|
|
<!-- Theme -->
|
|
<div class="bg-white rounded-lg p-4 shadow-sm border">
|
|
<h3 class="font-semibold mb-3 text-sm">主题</h3>
|
|
<div class="flex items-center gap-2 mb-2">
|
|
<input type="checkbox" id="theme-auto" v-model="settings.theme.auto" class="rounded" />
|
|
<label for="theme-auto" class="text-sm">自动跟随系统</label>
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<div>
|
|
<label class="text-xs text-gray-500">亮色主题</label>
|
|
<input v-model="settings.theme.light" class="w-full px-3 py-2 border rounded-lg text-sm" />
|
|
</div>
|
|
<div>
|
|
<label class="text-xs text-gray-500">暗色主题</label>
|
|
<input v-model="settings.theme.dark" class="w-full px-3 py-2 border rounded-lg text-sm" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- App name -->
|
|
<div class="bg-white rounded-lg p-4 shadow-sm border">
|
|
<h3 class="font-semibold mb-3 text-sm">应用</h3>
|
|
<div>
|
|
<label class="block text-sm mb-1">应用名称</label>
|
|
<input v-model="settings.appName" class="w-full px-3 py-2 border rounded-lg text-sm" />
|
|
</div>
|
|
</div>
|
|
|
|
<button class="px-4 py-2 bg-primary-600 text-white rounded-lg text-sm hover:bg-primary-700" @click="save">保存设置</button>
|
|
</div>
|
|
|
|
<div v-if="toast" class="fixed bottom-4 right-4 px-4 py-2 rounded-lg shadow-lg text-sm z-50"
|
|
:class="toast.type === 'error' ? 'bg-red-500 text-white' : 'bg-green-500 text-white'">
|
|
{{ toast.msg }}
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted } from 'vue'
|
|
import { getSettings, updateSettings } from '@/api'
|
|
|
|
const settings = ref(null)
|
|
const loading = ref(true)
|
|
const toast = ref(null)
|
|
|
|
function showToast(msg, type = 'success') {
|
|
toast.value = { msg, type }
|
|
setTimeout(() => toast.value = null, 2500)
|
|
}
|
|
|
|
async function save() {
|
|
try {
|
|
await updateSettings(settings.value)
|
|
showToast('设置已保存')
|
|
} catch (e) {
|
|
showToast(e.message, 'error')
|
|
}
|
|
}
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
const res = await getSettings()
|
|
settings.value = res.data
|
|
} catch (e) {
|
|
showToast(e.message, 'error')
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
})
|
|
</script>
|