Files
lingma-proxy-compose/desktop/frontend/src/views/Settings.vue
2026-04-29 18:45:25 +08:00

219 lines
7.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { computed, onMounted, ref } from 'vue'
import { GetConfig, UpdateConfig } from '../../wailsjs/go/main/App.js'
const emit = defineEmits(['log', 'status-refresh'])
const config = ref({})
const saving = ref(false)
const openSelect = ref('')
const selectOptions = {
Transport: [
{ value: 'auto', label: '自动' },
{ value: 'pipe', label: '命名管道' },
{ value: 'websocket', label: 'WebSocket' },
],
Mode: [
{ value: 'agent', label: 'Agent' },
{ value: 'chat', label: 'Chat' },
],
ShellType: [
{ value: 'zsh', label: 'zsh' },
{ value: 'bash', label: 'bash' },
{ value: 'powershell', label: 'PowerShell' },
{ value: 'cmd', label: 'cmd' },
],
SessionMode: [
{ value: 'auto', label: '自动' },
{ value: 'reuse', label: '复用' },
{ value: 'fresh', label: '每次新建' },
],
}
const selectLabel = computed(() => (field) => {
const option = selectOptions[field]?.find((item) => item.value === config.value[field])
return option?.label || '请选择'
})
function toggleSelect(field) {
openSelect.value = openSelect.value === field ? '' : field
}
function chooseOption(field, value) {
config.value[field] = value
openSelect.value = ''
}
onMounted(async () => {
try {
config.value = await GetConfig()
} catch (e) {
emit('log', 'error', '配置加载失败:' + (e.message || String(e)))
}
})
async function save() {
saving.value = true
try {
await UpdateConfig(config.value)
emit('log', 'info', '配置已保存,代理已按需重启')
emit('status-refresh')
} catch (e) {
emit('log', 'error', '配置保存失败:' + (e.message || String(e)))
} finally {
saving.value = false
}
}
</script>
<template>
<div class="page">
<div class="page-title">
<div>
<h1>设置</h1>
<p>配置监听地址Lingma 传输方式会话复用和请求超时</p>
</div>
<button class="primary-button" type="button" :disabled="saving" @click="save">
{{ saving ? '保存中...' : '保存并重启' }}
</button>
</div>
<section class="grid-2">
<div class="glass-panel">
<div class="panel-header">
<div>
<h2>服务监听</h2>
<p>第三方客户端连接本地代理使用这组地址</p>
</div>
</div>
<div class="form-grid">
<div class="field">
<label>主机</label>
<input v-model="config.Host" type="text" placeholder="127.0.0.1" />
</div>
<div class="field">
<label>端口</label>
<input v-model.number="config.Port" type="number" placeholder="8095" />
</div>
<div class="field">
<label>传输方式</label>
<div class="custom-select" :class="{ open: openSelect === 'Transport' }">
<button type="button" @click="toggleSelect('Transport')">
<span>{{ selectLabel('Transport') }}</span>
<i class="bi bi-chevron-down" aria-hidden="true"></i>
</button>
<div v-if="openSelect === 'Transport'" class="select-menu">
<button
v-for="option in selectOptions.Transport"
:key="option.value"
:class="{ selected: option.value === config.Transport }"
type="button"
@click="chooseOption('Transport', option.value)"
>
{{ option.label }}
</button>
</div>
</div>
</div>
<div class="field">
<label>超时秒数</label>
<input v-model.number="config.Timeout" type="number" min="1" />
</div>
<div class="field span-2">
<label>WebSocket 地址</label>
<input v-model="config.WebSocketURL" type="text" placeholder="留空自动探测 Lingma WebSocket" />
</div>
<div class="field span-2">
<label>命名管道</label>
<input v-model="config.Pipe" type="text" placeholder="留空自动探测 Windows Named Pipe" />
</div>
</div>
<div class="hint-box">
<strong>自动探测失败时</strong>
<span>先确认 VS Code / Lingma 插件已启动并登录macOS 通常填写 WebSocket例如 <code>ws://127.0.0.1:36510/</code>Windows 可填写命名管道,例如 <code>\\.\pipe\lingma-xxxx</code>,也可填写 WebSocket例如 <code>ws://127.0.0.1:36510/</code>。</span>
</div>
</div>
<div class="glass-panel">
<div class="panel-header">
<div>
<h2>会话与环境</h2>
<p>影响 Lingma 会话上下文和工具执行环境</p>
</div>
</div>
<div class="form-grid">
<div class="field">
<label>模式</label>
<div class="custom-select" :class="{ open: openSelect === 'Mode' }">
<button type="button" @click="toggleSelect('Mode')">
<span>{{ selectLabel('Mode') }}</span>
<i class="bi bi-chevron-down" aria-hidden="true"></i>
</button>
<div v-if="openSelect === 'Mode'" class="select-menu">
<button
v-for="option in selectOptions.Mode"
:key="option.value"
:class="{ selected: option.value === config.Mode }"
type="button"
@click="chooseOption('Mode', option.value)"
>
{{ option.label }}
</button>
</div>
</div>
</div>
<div class="field">
<label>Shell 类型</label>
<div class="custom-select" :class="{ open: openSelect === 'ShellType' }">
<button type="button" @click="toggleSelect('ShellType')">
<span>{{ selectLabel('ShellType') }}</span>
<i class="bi bi-chevron-down" aria-hidden="true"></i>
</button>
<div v-if="openSelect === 'ShellType'" class="select-menu">
<button
v-for="option in selectOptions.ShellType"
:key="option.value"
:class="{ selected: option.value === config.ShellType }"
type="button"
@click="chooseOption('ShellType', option.value)"
>
{{ option.label }}
</button>
</div>
</div>
</div>
<div class="field">
<label>会话策略</label>
<div class="custom-select" :class="{ open: openSelect === 'SessionMode' }">
<button type="button" @click="toggleSelect('SessionMode')">
<span>{{ selectLabel('SessionMode') }}</span>
<i class="bi bi-chevron-down" aria-hidden="true"></i>
</button>
<div v-if="openSelect === 'SessionMode'" class="select-menu">
<button
v-for="option in selectOptions.SessionMode"
:key="option.value"
:class="{ selected: option.value === config.SessionMode }"
type="button"
@click="chooseOption('SessionMode', option.value)"
>
{{ option.label }}
</button>
</div>
</div>
</div>
<div class="field">
<label>当前文件</label>
<input v-model="config.CurrentFilePath" type="text" placeholder="可选" />
</div>
<div class="field span-2">
<label>工作目录</label>
<textarea v-model="config.Cwd" placeholder="Lingma 创建 session 时使用的 cwd"></textarea>
</div>
</div>
</div>
</section>
</div>
</template>