| 123456789101112131415161718192021222324252627282930313233343536373839404142434445 |
- <script setup lang="ts">
- import { onMounted, ref } from 'vue'
- import { apiRequest } from '@/api/client'
- const emit = defineEmits<{ 'dirty-change': [value: boolean] }>()
- const deny = ref(true)
- const loading = ref(false), saving = ref(false), error = ref(''), saved = ref(false)
- async function load() {
- loading.value = true; error.value = ''
- try {
- const value = await apiRequest<{ denyServerTools: boolean }>('/api/app/settings/host-tools')
- deny.value = value.denyServerTools
- emit('dirty-change', false)
- } catch (cause) { error.value = cause instanceof Error ? cause.message : '无法读取服务端工具设置' }
- finally { loading.value = false }
- }
- function changed() { saved.value = false; emit('dirty-change', true) }
- async function save() {
- saving.value = true; error.value = ''; saved.value = false
- try {
- const value = await apiRequest<{ denyServerTools: boolean }>('/api/app/settings/host-tools', { method: 'PUT', body: { denyServerTools: deny.value } })
- deny.value = value.denyServerTools
- saved.value = true; emit('dirty-change', false)
- } catch (cause) { error.value = cause instanceof Error ? cause.message : '保存失败,请重试' }
- finally { saving.value = false }
- }
- onMounted(load)
- </script>
- <template>
- <section class="host-tools" aria-label="服务端工具">
- <p>控制 Bot 在服务端本机上能不能用终端和文件。默认禁用。已勾选的脚本机、脚本机浏览器、虚拟环境和云虚拟机不受这个开关影响。</p>
- <form @submit.prevent="save" @change="changed">
- <label class="toggle"><input v-model="deny" type="checkbox" :disabled="loading || saving" /><span><strong>禁用服务端本机的终端和文件</strong><small>开启后,Bot 对话不会拿到服务端的 terminal 和 file 工具。关掉之后,新开的会话才会放开,已经在跑的会话要重开一次。</small></span></label>
- <p v-if="error" class="error" role="alert">{{ error }}</p>
- <p v-if="saved" role="status">已保存。下一次开始或恢复的 Bot 会话会按这个设置执行。</p>
- <div class="actions"><button type="button" :disabled="loading || saving" @click="load">重新读取</button><button type="submit" class="save" :disabled="loading || saving">{{ saving ? '保存中…' : loading ? '读取中…' : '保存设置' }}</button></div>
- </form>
- </section>
- </template>
- <style scoped>
- .host-tools{display:grid;gap:18px;max-width:680px;color:var(--text-primary);font-size:13px;line-height:1.7}.host-tools p{margin:0}.host-tools small{display:block;color:var(--text-secondary);font-size:12px}.host-tools form{display:grid;gap:14px}.toggle{display:flex;gap:12px;align-items:flex-start;cursor:pointer}.toggle input{width:20px;height:20px;margin-top:2px;accent-color:var(--accent)}.actions{display:flex;gap:10px;justify-content:flex-end}.actions button{min-height:44px;padding:8px 16px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:var(--text-primary);font:inherit;cursor:pointer}.actions .save{background:var(--accent);color:var(--text-on-solid)}button:disabled{opacity:.55;cursor:default}.error{color:var(--danger)}input:focus-visible,button:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
- </style>
|