zhou zhou
11 小时以前 50e95b985a72fcec4a93a2470e9efdfb2620148a
rsf-design/src/views/system/ai-param/index.vue
@@ -13,14 +13,14 @@
    <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>
@@ -59,14 +59,14 @@
              <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>
@@ -84,25 +84,25 @@
                <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
@@ -110,15 +110,15 @@
                  :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">
@@ -146,6 +146,7 @@
<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'
@@ -172,6 +173,7 @@
  defineOptions({ name: 'AiParam' })
  const { t } = useI18n()
  const userStore = useUserStore()
  const searchForm = ref(createAiParamSearchState())
  const dialogVisible = ref(false)
@@ -183,41 +185,41 @@
  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 }
        ]
      }
    }
@@ -282,14 +284,14 @@
    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()
@@ -303,7 +305,7 @@
    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 {
@@ -315,17 +317,23 @@
  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'))
      }
    }
  }
@@ -341,12 +349,12 @@
        }),
        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)
@@ -357,9 +365,9 @@
      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
    }