|
|
|
@ -12,8 +12,10 @@ interface ModelOption { |
|
|
|
|
|
|
|
const models = ref<ModelOption[]>([]); |
|
|
|
const preferredModelId = ref<number | null>(null); |
|
|
|
const reviewApprovalMode = ref<string>("manual"); |
|
|
|
const loading = ref(false); |
|
|
|
const saving = ref(false); |
|
|
|
const savingApproval = ref(false); |
|
|
|
|
|
|
|
async function loadModels() { |
|
|
|
try { |
|
|
|
@ -37,6 +39,8 @@ async function loadUserConfig() { |
|
|
|
); |
|
|
|
const val = res.data?.config?.preferredLlmModelId; |
|
|
|
preferredModelId.value = typeof val === "number" && val > 0 ? val : null; |
|
|
|
const approvalVal = res.data?.config?.reviewApprovalMode; |
|
|
|
reviewApprovalMode.value = typeof approvalVal === "string" && ["manual", "all-pass"].includes(approvalVal) ? approvalVal : "manual"; |
|
|
|
} catch { |
|
|
|
preferredModelId.value = null; |
|
|
|
} |
|
|
|
@ -64,6 +68,23 @@ async function handleSave() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async function handleSaveApproval() { |
|
|
|
savingApproval.value = true; |
|
|
|
try { |
|
|
|
await $fetch("/api/config/me", { |
|
|
|
method: "PUT", |
|
|
|
body: { key: "reviewApprovalMode", value: reviewApprovalMode.value }, |
|
|
|
}); |
|
|
|
const { $toast } = useNuxtApp(); |
|
|
|
$toast?.success?.("审批设置已保存"); |
|
|
|
} catch { |
|
|
|
const { $toast } = useNuxtApp(); |
|
|
|
$toast?.error?.("保存失败,请稍后重试"); |
|
|
|
} finally { |
|
|
|
savingApproval.value = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
onMounted(async () => { |
|
|
|
loading.value = true; |
|
|
|
await Promise.all([loadModels(), loadUserConfig()]); |
|
|
|
@ -116,6 +137,60 @@ onMounted(async () => { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="settings-card"> |
|
|
|
<div class="card-header"> |
|
|
|
<h2 class="card-title">审批设置</h2> |
|
|
|
<p class="card-desc">Agent 调用工具时的审批策略</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="card-body"> |
|
|
|
<div class="approval-options"> |
|
|
|
<label |
|
|
|
class="approval-option" |
|
|
|
:class="{ active: reviewApprovalMode === 'manual' }" |
|
|
|
> |
|
|
|
<input |
|
|
|
v-model="reviewApprovalMode" |
|
|
|
type="radio" |
|
|
|
value="manual" |
|
|
|
class="approval-radio" |
|
|
|
/> |
|
|
|
<div class="approval-content"> |
|
|
|
<span class="approval-label">手动审批</span> |
|
|
|
<span class="approval-desc">每次工具调用需要您手动确认后才会执行</span> |
|
|
|
</div> |
|
|
|
</label> |
|
|
|
|
|
|
|
<label |
|
|
|
class="approval-option" |
|
|
|
:class="{ active: reviewApprovalMode === 'all-pass' }" |
|
|
|
> |
|
|
|
<input |
|
|
|
v-model="reviewApprovalMode" |
|
|
|
type="radio" |
|
|
|
value="all-pass" |
|
|
|
class="approval-radio" |
|
|
|
/> |
|
|
|
<div class="approval-content"> |
|
|
|
<span class="approval-label">全部通过</span> |
|
|
|
<span class="approval-desc">所有工具调用自动批准,无需手动确认</span> |
|
|
|
</div> |
|
|
|
</label> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="form-actions"> |
|
|
|
<button |
|
|
|
type="button" |
|
|
|
class="btn-primary" |
|
|
|
:disabled="savingApproval" |
|
|
|
@click="handleSaveApproval" |
|
|
|
> |
|
|
|
{{ savingApproval ? "保存中..." : "保存" }} |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
@ -247,4 +322,58 @@ onMounted(async () => { |
|
|
|
padding: 24px; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.approval-options { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 12px; |
|
|
|
} |
|
|
|
|
|
|
|
.approval-option { |
|
|
|
display: flex; |
|
|
|
align-items: flex-start; |
|
|
|
gap: 12px; |
|
|
|
padding: 16px; |
|
|
|
border: 1px solid var(--color-hairline); |
|
|
|
border-radius: 8px; |
|
|
|
cursor: pointer; |
|
|
|
transition: all 0.15s ease; |
|
|
|
} |
|
|
|
|
|
|
|
.approval-option:hover { |
|
|
|
border-color: var(--color-primary); |
|
|
|
} |
|
|
|
|
|
|
|
.approval-option.active { |
|
|
|
border-color: var(--color-primary); |
|
|
|
background: rgba(204, 120, 92, 0.05); |
|
|
|
} |
|
|
|
|
|
|
|
.approval-radio { |
|
|
|
margin-top: 2px; |
|
|
|
accent-color: var(--color-primary); |
|
|
|
cursor: pointer; |
|
|
|
} |
|
|
|
|
|
|
|
.approval-content { |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
gap: 4px; |
|
|
|
} |
|
|
|
|
|
|
|
.approval-label { |
|
|
|
font-size: 14px; |
|
|
|
font-weight: 500; |
|
|
|
color: var(--color-ink); |
|
|
|
} |
|
|
|
|
|
|
|
.approval-desc { |
|
|
|
font-size: 13px; |
|
|
|
color: var(--color-muted); |
|
|
|
line-height: 1.5; |
|
|
|
} |
|
|
|
|
|
|
|
.settings-card + .settings-card { |
|
|
|
margin-top: 24px; |
|
|
|
} |
|
|
|
</style> |
|
|
|
|