ChatSetting.vue 6.5 KB
<template>
  <a-card title="智能助手配置" class="config-card">
    <a-form :model="formState" layout="vertical" ref="formRef" :rules="rules">
      <!-- 向量模型 -->
      <a-form-item label="向量模型" class="form-item required" name="embeddingId">
        <a-select
          v-model:value="formState.embeddingId"
          placeholder="请选择向量模型"
          :options="options.embeddingOptions"
          show-search
          option-filter-prop="label"
        />
      </a-form-item>

      <!-- 大语言模型 -->
      <a-form-item label="大语言模型" class="form-item required" name="llmId">
        <a-select
          v-model:value="formState.llmId"
          placeholder="请选择大语言模型"
          :options="options.llmOptions"
          show-search
          option-filter-prop="label"
        />
      </a-form-item>

      <!-- 知识库 -->
      <a-form-item label="知识库" class="form-item required" name="knowledgeId">
        <a-select
          v-model:value="formState.knowledgeId"
          placeholder="请选择知识库"
          :options="options.knowledgeOptions"
          show-search
          option-filter-prop="label"
        />
      </a-form-item>

      <!-- 按钮(多选) -->
      <a-form-item label="功能按钮" class="form-item required" name="buttonIds">
        <a-select
          v-model:value="formState.buttonIds"
          mode="multiple"
          placeholder="请选择按钮"
          :options="options.buttonOptions"
          show-search
          option-filter-prop="label"
          :max-tag-count="6"
          :max="5"
        />
        <div class="hint">最多可选择5个按钮</div>
      </a-form-item>

      <!-- 提示词 -->
      <a-form-item label="提示词" class="form-item required" name="prompt">
        <a-textarea
          v-model:value="formState.prompt"
          placeholder="请输入提示词,例如:你是一个专业的AI助手..."
          :rows="9"
          :maxlength="500"
          show-count
        />
      </a-form-item>

      <!-- 操作按钮 -->
      <a-form-item class="action-buttons">
        <a-space>
          <a-button @click="resetForm">
            <template #icon><UndoOutlined /></template>
            重置
          </a-button>
          <a-button type="primary" @click="saveConfigData" :loading="saving">
            <template #icon><SaveOutlined /></template>
            保存配置
          </a-button>
        </a-space>
      </a-form-item>
    </a-form>
  </a-card>
</template>

<script lang="ts" setup>
  import { reactive, ref, onMounted } from 'vue';
  import { getConfigData, saveConfig } from './Chatsetting.api';
  import { FormInstance, message } from 'ant-design-vue';
  import { SaveOutlined, UndoOutlined } from '@ant-design/icons-vue';

  // 表单数据结构
  const formState = reactive({
    id: '',
    embeddingId: undefined,
    llmId: undefined,
    knowledgeId: undefined,
    buttonIds: [],
    prompt: '',
  });

  const formRef = ref<FormInstance>(); // 添加表单引用

  const rules = reactive({
    embeddingId: [{ required: true, message: '请选择向量模型', trigger: 'change' }],
    llmId: [{ required: true, message: '请选择大语言模型', trigger: 'change' }],
    knowledgeId: [{ required: true, message: '请选择知识库', trigger: 'change' }],
    buttonIds: [
      {
        required: true,
        message: '请至少选择一个按钮',
        trigger: 'change',
        type: 'array',
      },
    ],
    prompt: [
      { required: true, message: '请输入提示词', trigger: 'blur' },
      { max: 500, message: '提示词长度不能超过500个字符', trigger: 'blur' },
    ],
  });
  // 选项数据
  const options = reactive({
    embeddingOptions: [],
    llmOptions: [],
    knowledgeOptions: [],
    buttonOptions: [],
  });

  const saving = ref(false);

  // 加载配置数据
  const loadConfig = async () => {
    try {
      const res = await getConfigData();

      if (res.success) {
        const data = res.result;

        // 填充表单
        Object.keys(formState).forEach((key) => {
          if (data.airagChatsettingConfig[key] !== undefined) {
            if (key === 'buttonIds') {
              formState[key] = data.airagChatsettingConfig[key] || [];
            } else {
              formState[key] = data.airagChatsettingConfig[key];
            }
            console.log('shuju' + formState[key]);
          }
        });

        // 填充选项
        options.embeddingOptions = data.embeddingOptions || [];
        console.log('向量' + options.embeddingOptions);
        options.llmOptions = data.llmOptions || [];
        options.knowledgeOptions = data.knowledgeOptions || [];
        options.buttonOptions = data.buttonOptions || [];
      }
    } catch (error) {
      console.error('配置加载失败', error);
      message.error('配置加载失败');
    }
  };

  // 保存配置
  const saveConfigData = async () => {
    try {
      await formRef.value?.validateFields();
    } catch (error) {
      message.error('请填写所有必填字段');
      return;
    }
    const params = {
      ...formState,
      id: formState.id || '',
      buttonIds: formState.buttonIds.filter((id) => id && id !== 'undefined'),
    };
    if (formState.buttonIds.length > 5) {
      message.error('最多只能选择五个按钮');
      return;
    }
    saving.value = true;
    try {
      const res = await saveConfig(params);
      console.log(res.success);
      if (res.success) {
        message.success('配置保存成功');
        loadConfig(); // 重新加载最新数据
      } else {
        message.error('保存失败: ' + res.message);
      }
    } catch (error) {
      console.error('保存失败', error);
      message.error('保存失败');
    } finally {
      saving.value = false;
    }
  };

  // 重置表单
  const resetForm = () => {
    formRef.value?.resetFields();
  };

  // 初始化加载
  onMounted(() => {
    loadConfig();
  });
</script>

<style lang="less" scoped>
  .config-card {
    max-width: 1800px;
    margin: 20px auto;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);

    :deep(.ant-card-head) {
      background-color: #f0f5ff;
      border-bottom: 1px solid #e8e8e8;
    }
  }

  .form-item {
    margin-bottom: 24px;

    :deep(.ant-form-item-label) {
      font-weight: 500;
      margin-bottom: 8px;
    }
  }

  .hint {
    font-size: 12px;
    color: #999;
    margin-top: 4px;
  }

  .action-buttons {
    margin-top: 24px;
    text-align: center;

    .ant-space {
      justify-content: center;
    }

    .ant-btn {
      min-width: 120px;
    }
  }
</style>