SystemSettingsView.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <template>
  2. <div class="panel">
  3. <div class="toolbar">
  4. <div class="filters">
  5. <el-button type="primary" :loading="saving" @click="save">保存设置</el-button>
  6. <el-button @click="load">刷新</el-button>
  7. </div>
  8. </div>
  9. <el-form label-width="190px" class="settings-form">
  10. <div class="section-title">AI 默认参数</div>
  11. <el-form-item label="默认 AI 服务商">
  12. <el-select v-model="form.default_ai_provider_id" clearable placeholder="请选择" style="width: 360px" @change="selectDefaultModel">
  13. <el-option v-for="provider in enabledProviders" :key="provider.id" :label="provider.name" :value="provider.id" />
  14. </el-select>
  15. </el-form-item>
  16. <el-form-item label="默认 AI 模型">
  17. <el-select v-model="form.default_ai_model_id" clearable placeholder="请选择" style="width: 360px">
  18. <el-option v-for="model in providerModels" :key="model.id" :label="model.display_name || model.name" :value="model.id" />
  19. </el-select>
  20. </el-form-item>
  21. <el-form-item label="默认温度">
  22. <el-input-number v-model="form.default_ai_temperature" :min="0" :max="2" :step="0.1" />
  23. </el-form-item>
  24. <div class="section-title">文件保存路径</div>
  25. <el-alert type="info" show-icon :closable="false" title="路径保存为相对路径,并解析到后端 backend/data 目录下。" />
  26. <el-form-item label="自动化文件根路径">
  27. <el-input v-model="form.automation_file_root" placeholder="automation" />
  28. </el-form-item>
  29. <el-form-item label="已识别界面截图路径">
  30. <el-input v-model="form.automation_screen_path" placeholder="automation/screens" />
  31. </el-form-item>
  32. <el-form-item label="错误截图路径">
  33. <el-input v-model="form.automation_error_path" placeholder="automation/errors" />
  34. </el-form-item>
  35. <el-form-item label="临时截图路径">
  36. <el-input v-model="form.automation_runtime_path" placeholder="automation/runtime" />
  37. </el-form-item>
  38. <div class="section-title">自动化操作页</div>
  39. <el-form-item label="默认自动截屏">
  40. <el-switch v-model="form.automation_auto_screenshot_enabled" active-text="开启" inactive-text="关闭" />
  41. </el-form-item>
  42. <el-form-item label="自动截屏间隔秒数">
  43. <el-input-number v-model="form.automation_auto_screenshot_interval" :min="1" :max="3600" />
  44. </el-form-item>
  45. <div class="section-title">远程执行</div>
  46. <el-alert type="warning" show-icon :closable="false" title="远程执行和任务查询会校验此 Token。支持 X-Automation-Token、Bearer Token 或 automation_token 查询参数;请只在可信局域网或 VPN 内开放后端端口。" />
  47. <el-form-item label="远程执行 Token">
  48. <el-input v-model="form.automation_remote_token" show-password placeholder="用于 iOS 快捷指令和前端自动化请求" />
  49. </el-form-item>
  50. </el-form>
  51. </div>
  52. </template>
  53. <script setup>
  54. import { computed, onMounted, reactive, ref } from 'vue'
  55. import { ElMessage } from 'element-plus'
  56. import { api, setAutomationToken } from '../api'
  57. const providers = ref([])
  58. const models = ref([])
  59. const saving = ref(false)
  60. const form = reactive({
  61. default_ai_provider_id: null,
  62. default_ai_model_id: null,
  63. default_ai_temperature: 0.1,
  64. automation_file_root: 'automation',
  65. automation_screen_path: 'automation/screens',
  66. automation_error_path: 'automation/errors',
  67. automation_runtime_path: 'automation/runtime',
  68. automation_auto_screenshot_enabled: false,
  69. automation_auto_screenshot_interval: 30,
  70. automation_remote_token: '',
  71. })
  72. const enabledProviders = computed(() => providers.value.filter((item) => item.enabled))
  73. const providerModels = computed(() => models.value.filter((item) => item.provider_id === form.default_ai_provider_id))
  74. async function load() {
  75. const [settingsResult, providerResult, modelResult] = await Promise.all([
  76. api.get('/api/settings'),
  77. api.get('/api/ai/providers'),
  78. api.get('/api/ai/models'),
  79. ])
  80. providers.value = providerResult.data.items
  81. models.value = modelResult.data.items
  82. Object.assign(form, settingsResult.data.settings)
  83. syncAutomationToken()
  84. }
  85. function selectDefaultModel() {
  86. const available = providerModels.value
  87. if (!available.some((item) => item.id === form.default_ai_model_id)) {
  88. form.default_ai_model_id = available.find((item) => item.is_default)?.id || available[0]?.id || null
  89. }
  90. }
  91. async function save() {
  92. saving.value = true
  93. try {
  94. await api.put('/api/settings', form)
  95. syncAutomationToken()
  96. ElMessage.success('系统设置已保存')
  97. await load()
  98. } catch (error) {
  99. ElMessage.error(error.response?.data?.detail || '保存设置失败')
  100. } finally {
  101. saving.value = false
  102. }
  103. }
  104. function syncAutomationToken() {
  105. setAutomationToken(form.automation_remote_token)
  106. }
  107. defineExpose({ load })
  108. onMounted(load)
  109. </script>