refactor: optimize ai assistant settings actions

This commit is contained in:
jxxghp
2026-04-21 21:11:29 +08:00
parent 82cb903c1f
commit 6238849d3f
4 changed files with 164 additions and 55 deletions

View File

@@ -161,6 +161,7 @@ const llmModels = ref<string[]>([])
const loadingModels = ref(false)
const savingBasic = ref(false)
const testingLlm = ref(false)
const llmTestSuccessDialog = ref(false)
type LlmSettingsSnapshot = {
AI_AGENT_ENABLE: boolean
@@ -204,6 +205,7 @@ function invalidateLlmTestState() {
llmTestAbortController = null
}
testingLlm.value = false
llmTestSuccessDialog.value = false
llmTestResult.value = null
}
@@ -439,6 +441,7 @@ async function testLlmConnection() {
llmTestAbortController = abortController
testingLlm.value = true
llmTestSuccessDialog.value = false
llmTestResult.value = null
try {
const result: { [key: string]: any } = await api.post('system/llm-test', null, {
@@ -457,7 +460,7 @@ async function testLlmConnection() {
reply_preview: data.reply_preview,
message: result?.message,
}
if (result?.success) $toast.success(t('setting.system.llmTestSuccessToast'))
if (result?.success) llmTestSuccessDialog.value = true
else $toast.error(t('setting.system.llmTestFailedToast'))
} catch (error) {
if (requestId !== llmTestRequestId || abortController.signal.aborted || currentLlmSnapshotKey.value !== snapshotKey) {
@@ -1006,74 +1009,101 @@ watch(
</VCardText>
<VCardText>
<VForm @submit.prevent="() => {}">
<VAlert
v-if="SystemSettings.Basic.AI_AGENT_ENABLE && llmTestResult"
:type="llmTestResult.success ? 'success' : 'error'"
variant="tonal"
density="comfortable"
class="mb-4"
>
<div class="text-subtitle-2 mb-2">
{{ llmTestResult.success ? t('setting.system.llmTestSuccess') : t('setting.system.llmTestFailed') }}
</div>
<div class="text-body-2">
{{ t('setting.system.llmTestProviderValue', { value: llmTestResult.provider }) }}
</div>
<div class="text-body-2">
{{ t('setting.system.llmTestModelValue', { value: llmTestResult.model }) }}
</div>
<div v-if="llmTestResult.duration_ms !== undefined" class="text-body-2">
{{ t('setting.system.llmTestDurationValue', { duration: llmTestResult.duration_ms }) }}
</div>
<div v-if="llmTestResult.success && llmTestResult.reply_preview" class="text-body-2">
{{ t('setting.system.llmTestReplyPreviewValue', { value: llmTestResult.reply_preview }) }}
</div>
<div v-else-if="llmTestResult.message" class="text-body-2">
{{ t('setting.system.llmTestErrorMessageValue', { value: llmTestResult.message }) }}
</div>
</VAlert>
<div class="d-flex flex-wrap gap-4 mt-4">
<VRow v-if="SystemSettings.Basic.AI_AGENT_ENABLE" class="mt-1">
<VCol cols="12">
<VSheet
border
rounded="lg"
class="pa-4"
>
<div class="d-flex flex-column flex-md-row align-start align-md-center justify-space-between gap-4">
<div class="flex-1-1-auto">
<div class="text-subtitle-1 font-weight-medium">
{{ t('setting.system.llmTestPanelTitle') }}
</div>
<div class="text-body-2 text-medium-emphasis mt-1">
{{ t('setting.system.llmTestPanelDesc') }}
</div>
</div>
<div class="w-100 w-md-auto">
<VTooltip v-if="llmTestDisabledReason" location="top">
<template #activator="{ props }">
<span v-bind="props" class="d-flex">
<VBtn
color="secondary"
variant="tonal"
prepend-icon="mdi-connection"
:disabled="true"
:loading="testingLlm"
:block="!display.smAndUp.value"
class="text-no-wrap"
>
{{ t('setting.system.llmTestAction') }}
</VBtn>
</span>
</template>
<span>{{ llmTestDisabledReason }}</span>
</VTooltip>
<VBtn
v-else
color="secondary"
variant="tonal"
prepend-icon="mdi-connection"
:loading="testingLlm"
:block="!display.smAndUp.value"
class="text-no-wrap"
@click="testLlmConnection"
>
{{ t('setting.system.llmTestAction') }}
</VBtn>
</div>
</div>
<VAlert
v-if="llmTestResult && !llmTestResult.success"
type="error"
variant="tonal"
density="comfortable"
class="mt-4"
>
<div class="text-subtitle-2 mb-2">
{{ t('setting.system.llmTestFailed') }}
</div>
<div class="text-body-2">
{{ t('setting.system.llmTestProviderValue', { value: llmTestResult.provider }) }}
</div>
<div class="text-body-2">
{{ t('setting.system.llmTestModelValue', { value: llmTestResult.model }) }}
</div>
<div v-if="llmTestResult.duration_ms !== undefined" class="text-body-2">
{{ t('setting.system.llmTestDurationValue', { duration: llmTestResult.duration_ms }) }}
</div>
<div v-if="llmTestResult.message" class="text-body-2">
{{ t('setting.system.llmTestErrorMessageValue', { value: llmTestResult.message }) }}
</div>
</VAlert>
</VSheet>
</VCol>
</VRow>
<div class="setting-actions mt-4">
<VBtn
type="submit"
@click="saveBasicSettings"
prepend-icon="mdi-content-save"
:loading="savingBasic"
:disabled="testingLlm"
:block="!display.smAndUp.value"
class="text-no-wrap"
>
{{ t('common.save') }}
</VBtn>
<VTooltip v-if="SystemSettings.Basic.AI_AGENT_ENABLE && llmTestDisabledReason" location="top">
<template #activator="{ props }">
<span v-bind="props" class="d-inline-flex">
<VBtn
color="secondary"
variant="tonal"
prepend-icon="mdi-connection"
:disabled="true"
:loading="testingLlm"
>
{{ t('setting.system.llmTestAction') }}
</VBtn>
</span>
</template>
<span>{{ llmTestDisabledReason }}</span>
</VTooltip>
<VBtn
v-else-if="SystemSettings.Basic.AI_AGENT_ENABLE"
color="secondary"
variant="tonal"
prepend-icon="mdi-connection"
:loading="testingLlm"
@click="testLlmConnection"
>
{{ t('setting.system.llmTestAction') }}
</VBtn>
<VSpacer />
<VBtn
color="error"
@click="advancedDialog = true"
prepend-icon="mdi-cog"
append-icon="mdi-dots-horizontal"
:block="!display.smAndUp.value"
class="text-no-wrap setting-actions__secondary"
>
{{ t('setting.system.advancedSettings') }}
</VBtn>
@@ -1185,6 +1215,53 @@ watch(
</VCol>
</VRow>
<VDialog
v-if="llmTestSuccessDialog && llmTestResult?.success"
v-model="llmTestSuccessDialog"
max-width="34rem"
:fullscreen="display.xs.value"
>
<VCard>
<VCardItem class="py-3">
<template #prepend>
<VIcon icon="mdi-check-circle" color="success" class="me-2" />
</template>
<VCardTitle>{{ t('setting.system.llmTestSuccessDialogTitle') }}</VCardTitle>
<VCardSubtitle>{{ t('setting.system.llmTestSuccessDialogDesc') }}</VCardSubtitle>
</VCardItem>
<VDialogCloseBtn @click="llmTestSuccessDialog = false" />
<VCardText>
<VAlert
type="success"
variant="tonal"
density="comfortable"
>
{{ t('setting.system.llmTestSuccessToast') }}
</VAlert>
<div class="d-flex flex-column gap-2 mt-4">
<div class="text-body-1">
{{ t('setting.system.llmTestProviderValue', { value: llmTestResult.provider }) }}
</div>
<div class="text-body-1">
{{ t('setting.system.llmTestModelValue', { value: llmTestResult.model }) }}
</div>
<div v-if="llmTestResult.duration_ms !== undefined" class="text-body-1">
{{ t('setting.system.llmTestDurationValue', { duration: llmTestResult.duration_ms }) }}
</div>
<div v-if="llmTestResult.reply_preview" class="text-body-2 text-medium-emphasis">
{{ t('setting.system.llmTestReplyPreviewValue', { value: llmTestResult.reply_preview }) }}
</div>
</div>
</VCardText>
<VCardActions class="px-6 pb-6">
<VSpacer />
<VBtn color="primary" @click="llmTestSuccessDialog = false">
{{ t('common.close') }}
</VBtn>
</VCardActions>
</VCard>
</VDialog>
<!-- 高级系统设置 -->
<VDialog
v-if="advancedDialog"
@@ -1714,3 +1791,23 @@ watch(
</VCard>
</VDialog>
</template>
<style scoped>
.setting-actions {
display: flex;
gap: 1rem;
align-items: center;
justify-content: space-between;
}
.setting-actions__secondary {
flex-shrink: 0;
}
@media (max-width: 599px) {
.setting-actions {
flex-direction: column;
align-items: stretch;
}
}
</style>