feat: add desktop app release packaging
This commit is contained in:
218
desktop/frontend/src/views/Settings.vue
Normal file
218
desktop/frontend/src/views/Settings.vue
Normal file
@@ -0,0 +1,218 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user