| | |
| | | <ElCard class="art-table-card ai-param-list-card"> |
| | | <div class="mb-5 flex flex-wrap items-center justify-between gap-4"> |
| | | <div> |
| | | <h3 class="text-lg font-semibold text-[var(--art-gray-900)]">AI 参数</h3> |
| | | <p class="mt-1 text-sm text-[var(--art-gray-500)]">按卡片管理当前租户的模型接入参数与默认配置。</p> |
| | | <h3 class="text-lg font-semibold text-[var(--art-gray-900)]">{{ t('pages.system.aiParam.title') }}</h3> |
| | | <p class="mt-1 text-sm text-[var(--art-gray-500)]">{{ t('pages.system.aiParam.subtitle') }}</p> |
| | | </div> |
| | | |
| | | <ElSpace wrap> |
| | | <ElButton v-auth="'add'" @click="openCreateDialog" v-ripple>新建参数</ElButton> |
| | | <ElButton :loading="exportLoading" @click="handleExport" v-ripple>导出</ElButton> |
| | | <ElButton :loading="loading" @click="refreshData" v-ripple>刷新</ElButton> |
| | | <ElButton v-auth="'add'" @click="openCreateDialog" v-ripple>{{ t('pages.system.aiParam.buttons.add') }}</ElButton> |
| | | <ElButton :loading="exportLoading" @click="handleExport" v-ripple>{{ t('common.actions.export') }}</ElButton> |
| | | <ElButton :loading="loading" @click="refreshData" v-ripple>{{ t('common.actions.refresh') }}</ElButton> |
| | | </ElSpace> |
| | | </div> |
| | | |
| | |
| | | <div |
| | | class="min-w-0 rounded-2xl bg-slate-50 px-3 py-2.5" |
| | | > |
| | | <p class="text-xs text-[var(--art-gray-500)]">基础地址</p> |
| | | <p class="text-xs text-[var(--art-gray-500)]">{{ t('pages.system.aiParam.fields.baseUrl') }}</p> |
| | | <p class="mt-1.5 break-all text-sm leading-6 text-[var(--art-gray-900)]">{{ item.baseUrl || '--' }}</p> |
| | | </div> |
| | | <div |
| | | class="min-w-0 rounded-2xl bg-slate-50 px-3 py-2.5" |
| | | > |
| | | <p class="text-xs text-[var(--art-gray-500)]">最近校验</p> |
| | | <p class="mt-1.5 text-sm text-[var(--art-gray-900)]">{{ item['lastValidateTime$'] || '未校验' }}</p> |
| | | <p class="text-xs text-[var(--art-gray-500)]">{{ t('pages.system.aiParam.fields.lastValidateTime') }}</p> |
| | | <p class="mt-1.5 text-sm text-[var(--art-gray-900)]">{{ item['lastValidateTime$'] || t('pages.system.aiParam.validation.notTested') }}</p> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | <p class="mt-1 text-sm font-medium text-[var(--art-gray-900)]">{{ item.maxTokens ?? '--' }}</p> |
| | | </div> |
| | | <div class="min-w-0 rounded-2xl bg-slate-50 px-3 py-2"> |
| | | <p class="text-xs text-[var(--art-gray-500)]">超时时间</p> |
| | | <p class="text-xs text-[var(--art-gray-500)]">{{ t('pages.system.aiParam.fields.timeoutMs') }}</p> |
| | | <p class="mt-1 text-sm font-medium text-[var(--art-gray-900)]">{{ item.timeoutMs ?? '--' }} ms</p> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="mt-4 rounded-2xl bg-amber-50/70 px-3 py-2.5"> |
| | | <p class="text-xs text-[var(--art-gray-500)]">备注</p> |
| | | <p class="text-xs text-[var(--art-gray-500)]">{{ t('table.remark') }}</p> |
| | | <p class="mt-1.5 line-clamp-2 text-sm leading-6 text-[var(--art-gray-900)]">{{ item.memo || '--' }}</p> |
| | | </div> |
| | | |
| | | <div class="mt-4 flex flex-wrap items-center justify-between gap-3 border-t border-[var(--art-border-color)] pt-3"> |
| | | <div class="flex items-center gap-2 text-xs text-[var(--art-gray-500)]"> |
| | | <span>更新时间</span> |
| | | <span>{{ t('table.updateTime') }}</span> |
| | | <span>{{ item['updateTime$'] || '--' }}</span> |
| | | </div> |
| | | |
| | | <ElSpace wrap> |
| | | <ElButton text @click="openDetailDialog(item)">详情</ElButton> |
| | | <ElButton v-auth="'edit'" text @click="openEditDialog(item)">编辑</ElButton> |
| | | <ElButton text @click="openDetailDialog(item)">{{ t('common.actions.detail') }}</ElButton> |
| | | <ElButton v-auth="'edit'" text @click="openEditDialog(item)">{{ t('common.actions.edit') }}</ElButton> |
| | | <ElButton |
| | | v-auth="'edit'" |
| | | text |
| | |
| | | :loading="defaultUpdatingId === item.id" |
| | | @click="handleSetDefault(item)" |
| | | > |
| | | 设为默认 |
| | | {{ t('pages.system.aiParam.actions.setDefault') }} |
| | | </ElButton> |
| | | <ElButton v-auth="'delete'" text type="danger" @click="handleDelete(item)">删除</ElButton> |
| | | <ElButton v-auth="'delete'" text type="danger" @click="handleDelete(item)">{{ t('common.actions.delete') }}</ElButton> |
| | | </ElSpace> |
| | | </div> |
| | | </article> |
| | | </div> |
| | | |
| | | <ElEmpty v-else description="暂无 AI 参数数据" :image-size="110" /> |
| | | <ElEmpty v-else :description="t('pages.system.aiParam.empty')" :image-size="110" /> |
| | | </div> |
| | | |
| | | <div class="mt-6 flex justify-end"> |
| | |
| | | |
| | | <script setup> |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { useI18n } from 'vue-i18n' |
| | | import { useUserStore } from '@/store/modules/user' |
| | | import { useTable } from '@/hooks/core/useTable' |
| | | import { guardRequestWithMessage } from '@/utils/sys/requestGuard' |
| | |
| | | |
| | | defineOptions({ name: 'AiParam' }) |
| | | |
| | | const { t } = useI18n() |
| | | const userStore = useUserStore() |
| | | const searchForm = ref(createAiParamSearchState()) |
| | | const dialogVisible = ref(false) |
| | |
| | | |
| | | const searchItems = computed(() => [ |
| | | { |
| | | label: '关键字', |
| | | label: t('pages.system.aiParam.search.condition'), |
| | | key: 'condition', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入参数名称' |
| | | placeholder: t('pages.system.aiParam.search.conditionPlaceholder') |
| | | } |
| | | }, |
| | | { |
| | | label: '提供方', |
| | | label: t('pages.system.aiParam.search.providerType'), |
| | | key: 'providerType', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入提供方类型' |
| | | placeholder: t('pages.system.aiParam.search.providerTypePlaceholder') |
| | | } |
| | | }, |
| | | { |
| | | label: '模型', |
| | | label: t('pages.system.aiParam.search.model'), |
| | | key: 'model', |
| | | type: 'input', |
| | | props: { |
| | | clearable: true, |
| | | placeholder: '请输入模型名称' |
| | | placeholder: t('pages.system.aiParam.search.modelPlaceholder') |
| | | } |
| | | }, |
| | | { |
| | | label: '默认状态', |
| | | label: t('pages.system.aiParam.search.status'), |
| | | key: 'status', |
| | | type: 'select', |
| | | props: { |
| | | clearable: true, |
| | | options: [ |
| | | { label: '默认', value: 1 }, |
| | | { label: '候选', value: 0 } |
| | | { label: t('pages.system.aiParam.status.default'), value: 1 }, |
| | | { label: t('pages.system.aiParam.status.candidate'), value: 0 } |
| | | ] |
| | | } |
| | | } |
| | |
| | | try { |
| | | if (dialogMode.value === 'edit') { |
| | | await fetchUpdateAiParam(buildAiParamSavePayload(payload)) |
| | | ElMessage.success('修改成功') |
| | | ElMessage.success(t('crud.messages.updateSuccess')) |
| | | dialogVisible.value = false |
| | | summaryRefreshSeed.value += 1 |
| | | await refreshUpdate() |
| | | return |
| | | } |
| | | await fetchSaveAiParam(buildAiParamSavePayload(payload)) |
| | | ElMessage.success('新增成功') |
| | | ElMessage.success(t('crud.messages.createSuccess')) |
| | | dialogVisible.value = false |
| | | summaryRefreshSeed.value += 1 |
| | | await refreshCreate() |
| | |
| | | defaultUpdatingId.value = record.id |
| | | try { |
| | | await fetchSetAiParamDefault(record.id) |
| | | ElMessage.success('默认参数已切换') |
| | | ElMessage.success(t('pages.system.aiParam.messages.setDefaultSuccess')) |
| | | summaryRefreshSeed.value += 1 |
| | | await refreshUpdate() |
| | | } catch { |
| | |
| | | |
| | | async function handleDelete(record) { |
| | | try { |
| | | await ElMessageBox.confirm(`确定要删除 AI 参数「${record?.name || record?.id}」吗?`, '删除确认', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | await ElMessageBox.confirm( |
| | | t('crud.confirm.deleteMessage', { |
| | | entity: t('pages.system.aiParam.entity'), |
| | | label: record?.name || record?.id |
| | | }), |
| | | t('crud.confirm.deleteTitle'), |
| | | { |
| | | confirmButtonText: t('common.confirm'), |
| | | cancelButtonText: t('common.cancel'), |
| | | type: 'warning' |
| | | }) |
| | | await fetchDeleteAiParam(record.id) |
| | | ElMessage.success('删除成功') |
| | | ElMessage.success(t('crud.messages.deleteSuccess')) |
| | | await refreshRemove() |
| | | } catch (error) { |
| | | if (error !== 'cancel') { |
| | | ElMessage.error(error?.message || '删除失败') |
| | | ElMessage.error(error?.message || t('crud.messages.deleteFailed')) |
| | | } |
| | | } |
| | | } |
| | |
| | | }), |
| | | null, |
| | | { |
| | | timeoutMessage: '导出请求超时,已停止等待' |
| | | timeoutMessage: t('message.exportTimeoutStopped') |
| | | } |
| | | ) |
| | | if (!response) return |
| | | if (!response.ok) { |
| | | throw new Error(`导出失败 (${response.status})`) |
| | | throw new Error(t('crud.messages.exportFailedWithStatus', { status: response.status })) |
| | | } |
| | | const blob = await response.blob() |
| | | const url = window.URL.createObjectURL(blob) |
| | |
| | | link.click() |
| | | link.remove() |
| | | window.URL.revokeObjectURL(url) |
| | | ElMessage.success('导出成功') |
| | | ElMessage.success(t('crud.messages.exportSuccess')) |
| | | } catch (error) { |
| | | ElMessage.error(error?.message || '导出失败') |
| | | ElMessage.error(error?.message || t('crud.messages.exportFailed')) |
| | | } finally { |
| | | exportLoading.value = false |
| | | } |