| | |
| | | :show-submit="false" |
| | | /> |
| | | |
| | | <div v-if="showRuntimeSection" class="mt-2 rounded-2xl border border-[var(--art-border-color)] px-5 py-4"> |
| | | <div |
| | | v-if="showRuntimeSection" |
| | | class="mt-2 rounded-2xl border border-[var(--art-border-color)] px-5 py-4" |
| | | > |
| | | <div class="mb-3 flex items-center justify-between gap-4"> |
| | | <div> |
| | | <h4 class="text-base font-semibold text-[var(--art-gray-900)]">运行时状态</h4> |
| | | <p class="mt-1 text-sm text-[var(--art-gray-500)]">保存前可先执行草稿校验,运行时状态由后端真实返回。</p> |
| | | <h4 class="text-base font-semibold text-[var(--art-gray-900)]"> |
| | | {{ t('pages.system.aiParam.dialog.runtimeTitle') }} |
| | | </h4> |
| | | <p class="mt-1 text-sm text-[var(--art-gray-500)]"> |
| | | {{ t('pages.system.aiParam.dialog.runtimeDescription') }} |
| | | </p> |
| | | </div> |
| | | <ElButton v-if="!isReadonly" :loading="validateLoading" @click="handleValidateDraft"> |
| | | 草稿校验 |
| | | {{ t('pages.system.aiParam.dialog.validateDraft') }} |
| | | </ElButton> |
| | | </div> |
| | | |
| | |
| | | /> |
| | | |
| | | <ElDescriptions :column="2" border> |
| | | <ElDescriptionsItem label="校验状态">{{ form.validateStatus || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="最近校验耗时"> |
| | | {{ form.lastValidateElapsedMs !== null && form.lastValidateElapsedMs !== undefined ? `${form.lastValidateElapsedMs} ms` : '--' }} |
| | | <ElDescriptionsItem :label="t('pages.system.aiParam.dialog.labels.validateStatus')"> |
| | | {{ form.validateStatus || '--' }} |
| | | </ElDescriptionsItem> |
| | | <ElDescriptionsItem label="最近校验时间">{{ form['lastValidateTime$'] || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="最近更新人">{{ form.updateBy || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="最近更新时间" :span="2">{{ form['updateTime$'] || '--' }}</ElDescriptionsItem> |
| | | <ElDescriptionsItem label="最近校验信息" :span="2"> |
| | | <ElDescriptionsItem :label="t('pages.system.aiParam.dialog.labels.lastValidateElapsedMs')"> |
| | | {{ |
| | | form.lastValidateElapsedMs !== null && form.lastValidateElapsedMs !== undefined |
| | | ? `${form.lastValidateElapsedMs} ms` |
| | | : '--' |
| | | }} |
| | | </ElDescriptionsItem> |
| | | <ElDescriptionsItem :label="t('pages.system.aiParam.dialog.labels.lastValidateTime')"> |
| | | {{ form['lastValidateTime$'] || '--' }} |
| | | </ElDescriptionsItem> |
| | | <ElDescriptionsItem :label="t('pages.system.aiParam.dialog.labels.updateBy')"> |
| | | {{ form.updateBy || '--' }} |
| | | </ElDescriptionsItem> |
| | | <ElDescriptionsItem :label="t('pages.system.aiParam.dialog.labels.updateTime')" :span="2"> |
| | | {{ form['updateTime$'] || '--' }} |
| | | </ElDescriptionsItem> |
| | | <ElDescriptionsItem |
| | | :label="t('pages.system.aiParam.dialog.labels.lastValidateMessage')" |
| | | :span="2" |
| | | > |
| | | <div class="whitespace-pre-wrap break-all text-sm leading-6 text-[var(--art-gray-700)]"> |
| | | {{ form.lastValidateMessage || '--' }} |
| | | </div> |
| | |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <ElButton @click="handleCancel">{{ isReadonly ? '关闭' : '取消' }}</ElButton> |
| | | <ElButton v-if="!isReadonly" type="primary" @click="handleSubmit">确定</ElButton> |
| | | <ElButton @click="handleCancel"> |
| | | {{ isReadonly ? t('common.actions.close') : t('common.cancel') }} |
| | | </ElButton> |
| | | <ElButton v-if="!isReadonly" type="primary" @click="handleSubmit"> |
| | | {{ t('common.confirm') }} |
| | | </ElButton> |
| | | </span> |
| | | </template> |
| | | </ElDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { useI18n } from 'vue-i18n' |
| | | import ArtForm from '@/components/core/forms/art-form/index.vue' |
| | | import { fetchValidateAiParamDraft } from '@/api/ai-config' |
| | | import { |
| | |
| | | }) |
| | | |
| | | const emit = defineEmits(['submit', 'update:visible']) |
| | | const { t } = useI18n() |
| | | const formRef = ref() |
| | | const form = reactive(createAiParamFormState()) |
| | | const validateLoading = ref(false) |
| | |
| | | const isReadonly = computed(() => props.mode === 'show') |
| | | const showRuntimeSection = computed(() => Boolean(form.id) || props.mode !== 'create') |
| | | const dialogTitle = computed(() => { |
| | | if (props.mode === 'edit') return '编辑 AI 参数' |
| | | if (props.mode === 'show') return 'AI 参数详情' |
| | | return '新建 AI 参数' |
| | | if (props.mode === 'edit') return t('pages.system.aiParam.dialog.titleEdit') |
| | | if (props.mode === 'show') return t('pages.system.aiParam.dialog.titleDetail') |
| | | return t('pages.system.aiParam.dialog.titleCreate') |
| | | }) |
| | | |
| | | const validateAlertType = computed(() => |
| | |
| | | }) |
| | | |
| | | const rules = computed(() => ({ |
| | | name: [{ required: true, message: '请输入参数名称', trigger: 'blur' }], |
| | | providerType: [{ required: true, message: '请选择提供方类型', trigger: 'change' }], |
| | | baseUrl: [{ required: true, message: '请输入基础地址', trigger: 'blur' }], |
| | | apiKey: [{ required: true, message: '请输入 API Key', trigger: 'blur' }], |
| | | model: [{ required: true, message: '请输入模型名称', trigger: 'blur' }] |
| | | name: [{ required: true, message: t('pages.system.aiParam.dialog.validation.name'), trigger: 'blur' }], |
| | | providerType: [ |
| | | { |
| | | required: true, |
| | | message: t('pages.system.aiParam.dialog.validation.providerType'), |
| | | trigger: 'change' |
| | | } |
| | | ], |
| | | baseUrl: [{ required: true, message: t('pages.system.aiParam.dialog.validation.baseUrl'), trigger: 'blur' }], |
| | | apiKey: [{ required: true, message: t('pages.system.aiParam.dialog.validation.apiKey'), trigger: 'blur' }], |
| | | model: [{ required: true, message: t('pages.system.aiParam.dialog.validation.model'), trigger: 'blur' }] |
| | | })) |
| | | |
| | | const formItems = computed(() => [ |
| | | { |
| | | label: '参数名称', |
| | | label: t('pages.system.aiParam.dialog.labels.name'), |
| | | key: 'name', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入参数名称', |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.name'), |
| | | disabled: isReadonly.value |
| | | } |
| | | }, |
| | | { |
| | | label: '提供方类型', |
| | | label: t('pages.system.aiParam.dialog.labels.providerType'), |
| | | key: 'providerType', |
| | | type: 'select', |
| | | props: { |
| | | options: getAiParamProviderOptions(), |
| | | disabled: isReadonly.value, |
| | | placeholder: '请选择提供方类型' |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.providerType') |
| | | } |
| | | }, |
| | | { |
| | | label: '基础地址', |
| | | label: t('pages.system.aiParam.dialog.labels.baseUrl'), |
| | | key: 'baseUrl', |
| | | type: 'input', |
| | | span: 24, |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入兼容 OpenAI 的基础地址', |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.baseUrl'), |
| | | disabled: isReadonly.value |
| | | } |
| | | }, |
| | | { |
| | | label: 'API Key', |
| | | label: t('pages.system.aiParam.dialog.labels.apiKey'), |
| | | key: 'apiKey', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入 API Key', |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.apiKey'), |
| | | disabled: isReadonly.value, |
| | | type: isReadonly.value ? 'text' : 'password', |
| | | showPassword: !isReadonly.value |
| | | } |
| | | }, |
| | | { |
| | | label: '模型名称', |
| | | label: t('pages.system.aiParam.dialog.labels.model'), |
| | | key: 'model', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入模型名称', |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.model'), |
| | | disabled: isReadonly.value |
| | | } |
| | | }, |
| | | { |
| | | label: 'Temperature', |
| | | label: t('pages.system.aiParam.dialog.labels.temperature'), |
| | | key: 'temperature', |
| | | type: 'number', |
| | | props: { |
| | |
| | | max: 2, |
| | | step: 0.1, |
| | | precision: 2, |
| | | placeholder: '请输入 temperature', |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.temperature'), |
| | | disabled: isReadonly.value |
| | | } |
| | | }, |
| | | { |
| | | label: 'Top P', |
| | | label: t('pages.system.aiParam.dialog.labels.topP'), |
| | | key: 'topP', |
| | | type: 'number', |
| | | props: { |
| | |
| | | max: 1, |
| | | step: 0.1, |
| | | precision: 2, |
| | | placeholder: '请输入 topP', |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.topP'), |
| | | disabled: isReadonly.value |
| | | } |
| | | }, |
| | | { |
| | | label: '最大 Token', |
| | | label: t('pages.system.aiParam.dialog.labels.maxTokens'), |
| | | key: 'maxTokens', |
| | | type: 'number', |
| | | props: { |
| | | min: 1, |
| | | step: 1, |
| | | placeholder: '请输入最大 token', |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.maxTokens'), |
| | | disabled: isReadonly.value |
| | | } |
| | | }, |
| | | { |
| | | label: '超时时间(ms)', |
| | | label: t('pages.system.aiParam.dialog.labels.timeoutMs'), |
| | | key: 'timeoutMs', |
| | | type: 'number', |
| | | props: { |
| | | min: 1000, |
| | | step: 1000, |
| | | placeholder: '请输入超时时间', |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.timeoutMs'), |
| | | disabled: isReadonly.value |
| | | } |
| | | }, |
| | | { |
| | | label: '流式响应', |
| | | label: t('pages.system.aiParam.dialog.labels.streamingEnabled'), |
| | | key: 'streamingEnabled', |
| | | type: 'switch', |
| | | props: { |
| | | disabled: isReadonly.value, |
| | | activeText: '开启', |
| | | inactiveText: '关闭' |
| | | activeText: t('common.status.enabled'), |
| | | inactiveText: t('common.status.disabled') |
| | | } |
| | | }, |
| | | { |
| | | label: '默认状态', |
| | | label: t('pages.system.aiParam.dialog.labels.status'), |
| | | key: 'status', |
| | | type: 'select', |
| | | props: { |
| | | disabled: isReadonly.value, |
| | | options: getAiParamStatusOptions(), |
| | | placeholder: '请选择默认状态' |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.status') |
| | | } |
| | | }, |
| | | { |
| | | label: '备注', |
| | | label: t('pages.system.aiParam.dialog.labels.memo'), |
| | | key: 'memo', |
| | | type: 'input', |
| | | span: 24, |
| | |
| | | disabled: isReadonly.value, |
| | | type: 'textarea', |
| | | rows: 3, |
| | | placeholder: '请输入备注' |
| | | placeholder: t('pages.system.aiParam.dialog.placeholders.memo') |
| | | } |
| | | } |
| | | ]) |