Coze源码分析-资源库-创建知识库-前端源码-核心组件

概述

本文深入分析Coze Studio中用户创建知识库功能的前端实现。该功能允许用户在资源库中创建、编辑和管理知识库资源,为开发者提供了强大的知识管理和数据处理能力。通过对源码的详细解析,我们将了解从资源库入口到知识库配置弹窗的完整架构设计、组件实现、状态管理和用户体验优化等核心技术要点。

功能特性

核心功能

  • 知识库创建:支持自定义知识库名称、描述和图标配置
  • 知识库管理:提供知识库列表展示、编辑和删除功能
  • 多种知识库类型:支持文本、表格、图片三种格式类型
  • 数据源配置:支持本地上传、在线导入等多种数据来源
  • 状态管理:支持知识库启用/禁用状态切换

用户体验特性

  • 即时反馈:操作结果实时展示和验证
  • 表单验证:完善的知识库信息验证机制
  • 便捷操作:支持一键创建并上传、快速编辑
  • 国际化支持:多语言界面适配

技术架构

整体架构设计

复制代码
┌─────────────────────────────────────────────────────────────┐
│                      知识库管理模块                          │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │ LibraryPage │  │LibraryHeader│  │CreateKnowledge      │  │
│  │ (资源库页面) │  │ (添加按钮)  │  │     ModalV2         │  │
│  └─────────────┘  └─────────────┘  │  (创建/编辑弹窗)    │  │
│  ┌─────────────┐  ┌─────────────┐  └─────────────────────┘  │
│  │BaseLibrary  │  │   Table     │  ┌─────────────────────┐  │
│  │    Page     │  │ (资源列表)  │  │CozeKnowledgeAdd     │  │
│  └─────────────┘  └─────────────┘  │TypeContent(表单组件)│  │
│                                    └─────────────────────┘  │
├─────────────────────────────────────────────────────────────┤
│                      状态管理层                             │
│  ┌─────────────────┐  ┌─────────────────────────────────┐  │
│  │useKnowledgeConfig│  │         API Hooks               │  │
│  │  (配置逻辑)      │  │       KnowledgeApi              │  │
│  └─────────────────┘  └─────────────────────────────────┘  │
├─────────────────────────────────────────────────────────────┤
│                       API服务层                            │
│  ┌─────────────────────────────────────────────────────────┐
│  │              Knowledge API                              │
│  │         CreateDataset/DeleteDataset/UpdateDataset      │
│  └─────────────────────────────────────────────────────────┘
└────────────────────────────────────────────────────────────┘

核心模块结构

复制代码
frontend/
├── apps/coze-studio/src/
│   └── pages/
│       ├── library.tsx            # 资源库入口页面
│       └── knowledge/
│           ├── layout.tsx         # 知识库页面布局
│           ├── page.tsx           # 知识库详情页面
│           └── upload/            # 知识库上传相关
├── packages/studio/workspace/
│   ├── entry-adapter/src/pages/library/
│   │   └── index.tsx              # LibraryPage适配器组件
│   └── entry-base/src/pages/library/
│       ├── index.tsx              # BaseLibraryPage核心组件
│       ├── components/
│       │   └── library-header.tsx # LibraryHeader头部组件
│       └── hooks/use-entity-configs/
│           └── use-knowledge-config.tsx  # 知识库配置Hook
├── packages/data/knowledge/
│   ├── knowledge-modal-adapter/src/
│   │   └── create-knowledge-modal-v2/
│   │       └── scenes/base/
│   │           └── index.tsx      # useCreateKnowledgeModalV2 Hook
│   ├── knowledge-modal-base/src/
│   │   └── create-knowledge-modal-v2/
│   │       └── features/add-type-content/
│   │           └── coze-knowledge/
│   │               └── index.tsx  # CozeKnowledgeAddTypeContent组件
│   └── knowledge-stores/src/
│       └── hooks.ts               # 知识库状态管理Hook
├── packages/arch/idl/src/auto-generated/
│   └── knowledge/
│       └── namespaces/
│           └── knowledge.ts       # 知识库相关类型定义
└── packages/arch/bot-api/src/
    └── knowledge-api.ts           # KnowledgeApi定义

用户创建知识库流程概述

复制代码
用户登录Coze Studio
        ↓
  点击"资源库"菜单
        ↓
  LibraryPage 组件加载
        ↓
  点击右上角"+"按钮
        ↓
  LibraryHeader 显示创建菜单
        ↓
  点击"知识库"选项
        ↓
  openCreateKnowledgeModal() 触发
        ↓
  CreateKnowledgeModalV2 弹窗显示
        ↓
  用户选择知识库格式类型(文本/表格/图片)
        ↓
  用户输入知识库名称(name字段)
        ↓
  用户输入知识库描述(description字段)
        ↓
  用户选择数据导入类型和上传图标
        ↓
  表单验证(名称必填,描述可选)
        ↓
  用户点击"创建"或"创建并导入"按钮
        ↓
  createDataset() 触发
        ↓
  KnowledgeApi.CreateDataset() 调用
        ↓
  后端创建新知识库资源
        ↓
  onFinish() 处理成功响应
        ↓
  导航到知识库详情页面(可选择是否进入上传页面)
        ↓
  刷新资源库列表

该流程包含多层验证和处理:

  1. 前端表单验证:通过Form组件进行名称等必填字段验证
  2. 知识库类型选择:支持文本、表格、图片三种格式类型
  3. API调用:使用KnowledgeApi.CreateDataset API处理知识库创建
  4. 成功处理:创建成功后可选择直接进入上传页面或知识库详情页面
  5. 状态管理:通过useKnowledgeConfig Hook管理弹窗状态和数据流
    整个流程确保了知识库创建的便捷性和用户体验的流畅性。

核心组件实现

组件层次结构

知识库创建功能涉及多个层次的组件:

  1. LibraryPage组件:资源库主页面
  2. BaseLibraryPage组件:资源库核心逻辑
  3. LibraryHeader组件:包含创建按钮的头部
  4. CreateKnowledgeModalV2组件:知识库配置弹窗
  5. CozeKnowledgeAddTypeContent组件:知识库表单组件

1. 资源库入口组件(LibraryPage)

文件位置:frontend/packages/studio/workspace/entry-adapter/src/pages/library/index.tsx

作为资源库的适配器组件,整合各种资源配置:

typescript 复制代码
import { type FC, useRef } from 'react';

import {
  BaseLibraryPage,
  useDatabaseConfig,
  usePluginConfig,
  useWorkflowConfig,
  usePromptConfig,
  useKnowledgeConfig,
} from '@coze-studio/workspace-base/library';

export const LibraryPage: FC<{ spaceId: string }> = ({ spaceId }) => {
  const basePageRef = useRef<{ reloadList: () => void }>(null);
  const configCommonParams = {
    spaceId,
    reloadList: () => {
      basePageRef.current?.reloadList();
    },
  };
  const { config: pluginConfig, modals: pluginModals } =
    usePluginConfig(configCommonParams);
  const { config: workflowConfig, modals: workflowModals } =
    useWorkflowConfig(configCommonParams);
  const { config: knowledgeConfig, modals: knowledgeModals } =
    useKnowledgeConfig(configCommonParams);
  const { config: promptConfig, modals: promptModals } =
    usePromptConfig(configCommonParams);
  const { config: databaseConfig, modals: databaseModals } =
    useDatabaseConfig(configCommonParams);

  return (
    <>
      <BaseLibraryPage
        spaceId={spaceId}
        ref={basePageRef}
        entityConfigs={[
          pluginConfig,
          workflowConfig,
          knowledgeConfig,
          promptConfig,
          databaseConfig,
        ]}
      />
      {pluginModals}
      {workflowModals}
      {promptModals}
      {databaseModals}
      {knowledgeModals}
    </>
  );
};
      <ResultModal
        visible={!!successData}
        data={successData}
        onOk={refresh}
      />
    </>
  );
};

设计亮点

  • 状态集中管理 :通过 usePatOperation Hook统一管理组件状态
  • 组件解耦:各子组件职责明确,通过props进行通信
  • 数据流清晰:单向数据流,状态变更可追踪

2. 资源库核心组件(BaseLibraryPage)

文件位置:frontend/packages/studio/workspace/entry-base/src/pages/library/index.tsx

负责资源库的核心展示逻辑:

typescript 复制代码
import { forwardRef, useImperativeHandle } from 'react';

import classNames from 'classnames';
import { useInfiniteScroll } from 'ahooks';
import { I18n } from '@coze-arch/i18n';
import {
  Table,
  Select,
  Search,
  Layout,
  Cascader,
  Space,
} from '@coze-arch/coze-design';
import { renderHtmlTitle } from '@coze-arch/bot-utils';
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
import {
  type ResType,
  type LibraryResourceListRequest,
  type ResourceInfo,
} from '@coze-arch/idl/plugin_develop';
import { PluginDevelopApi } from '@coze-arch/bot-api';

import { type ListData, type BaseLibraryPageProps } from './types';
import { LibraryHeader } from './components/library-header';

export const BaseLibraryPage = forwardRef<
  { reloadList: () => void },
  BaseLibraryPageProps
>(
  ({ spaceId, isPersonalSpace = true, entityConfigs }, ref) => {
    const { params, setParams, resetParams, hasFilter, ready } =
      useCachedQueryParams({
        spaceId,
      });

    const listResp = useInfiniteScroll<ListData>(
      async prev => {
        if (!ready) {
          return {
            list: [],
            nextCursorId: undefined,
            hasMore: false,
          };
        }
        const resp = await PluginDevelopApi.LibraryResourceList(
          entityConfigs.reduce<LibraryResourceListRequest>(
            (res, config) => config.parseParams?.(res) ?? res,
            {
              ...params,
              cursor: prev?.nextCursorId,
              space_id: spaceId,
              size: LIBRARY_PAGE_SIZE,
            },
          ),
        );
        return {
          list: resp?.resource_list || [],
          nextCursorId: resp?.cursor,
          hasMore: !!resp?.has_more,
        };
      },
      {
        reloadDeps: [params, spaceId],
      },
    );

    useImperativeHandle(ref, () => ({
      reloadList: listResp.reload,
    }));

    return (
      <Layout
        className={s['layout-content']}
        title={renderHtmlTitle(I18n.t('navigation_workspace_library'))}
      >
        <Layout.Header className={classNames(s['layout-header'], 'pb-0')}>
          <div className="w-full">
            <LibraryHeader entityConfigs={entityConfigs} />
            {/* 过滤器组件 */}
          </div>
        </Layout.Header>
        <Layout.Content>
          {/* 表格和列表内容 */}
        </Layout.Content>
      </Layout>
    );
  }
);

3. 资源库头部组件(LibraryHeader)

文件位置:frontend/packages/studio/workspace/entry-base/src/pages/library/components/library-header.tsx

包含创建资源的入口按钮:

typescript 复制代码
import React from 'react';

import { I18n } from '@coze-arch/i18n';
import { IconCozPlus } from '@coze-arch/coze-design/icons';
import { Button, Menu } from '@coze-arch/coze-design';

import { type LibraryEntityConfig } from '../types';

export const LibraryHeader: React.FC<{
  entityConfigs: LibraryEntityConfig[];
}> = ({ entityConfigs }) => (
  <div className="flex items-center justify-between mb-[16px]">
    <div className="font-[500] text-[20px]">
      {I18n.t('navigation_workspace_library')}
    </div>
    <Menu
      position="bottomRight"
      className="w-120px mt-4px mb-4px"
      render={
        <Menu.SubMenu mode="menu">
          {entityConfigs.map(config => config.renderCreateMenu?.() ?? null)}
        </Menu.SubMenu>
      }
    >
      <Button
        theme="solid"
        type="primary"
        icon={<IconCozPlus />}
        data-testid="workspace.library.header.create"
      >
        {I18n.t('library_resource')}
      </Button>
    </Menu>
  </div>
);

4. 知识库配置Hook(useKnowledgeConfig)

文件位置:frontend/packages/studio/workspace/entry-base/src/pages/library/hooks/use-entity-configs/use-knowledge-config.tsx

管理知识库创建和编辑的状态:

typescript 复制代码
import { useNavigate } from 'react-router-dom';

import { useRequest } from 'ahooks';
import { useCreateKnowledgeModalV2 } from '@coze-data/knowledge-modal-adapter';
import {
  ActionKey,
  type ResourceInfo,
  ResType,
} from '@coze-arch/idl/plugin_develop';
import { DatasetStatus } from '@coze-arch/idl/knowledge';
import { I18n, type I18nKeysNoOptionsType } from '@coze-arch/i18n';
import { IconCozClock, IconCozKnowledge } from '@coze-arch/coze-design/icons';
import { Menu, Switch, Tag, Toast, Table } from '@coze-arch/coze-design';
import { KnowledgeApi } from '@coze-arch/bot-api';
import { safeJSONParse } from '@coze-agent-ide/space-bot/util';

import { BaseLibraryItem } from '../../components/base-library-item';
import DocDefaultIcon from '../../assets/doc_default_icon.png';
import { type UseEntityConfigHook } from './types';

const { TableAction } = Table;

/**
 * Knowledge base tags:
 * 0-text
 * 1-table
 * 2-image
 * */
const knowledgeSubTypeTextMap: Record<number, I18nKeysNoOptionsType> = {
  0: 'library_filter_tags_text',
  1: 'library_filter_tags_table',
  2: 'library_filter_tags_image',
};

export const useKnowledgeConfig: UseEntityConfigHook = ({
  spaceId,
  reloadList,
  getCommonActions,
}) => {
  const navigate = useNavigate();
  const {
    modal: createKnowledgeModal,
    open: openCreateKnowledgeModal,
    close: closeCreateKnowledgeModal,
  } = useCreateKnowledgeModalV2({
    onFinish: (datasetID, unitType, shouldUpload) => {
      navigate(
        `/space/${spaceId}/knowledge/${datasetID}${
          shouldUpload ? '/upload' : ''
        }?type=${unitType}&from=create`,
      );
      closeCreateKnowledgeModal();
    },
  });

  // delete
  const { run: delKnowledge } = useRequest(
    (datasetId: string) =>
      KnowledgeApi.DeleteDataset({
        dataset_id: datasetId,
      }),
    {
      manual: true,
      onSuccess: () => {
        reloadList();
        Toast.success(I18n.t('Delete_success'));
      },
    },
  );

  return {
    modals: <>{createKnowledgeModal}</>,
    config: {
      typeFilter: {
        label: I18n.t('library_resource_type_knowledge'),
        value: ResType.Knowledge,
      },
      renderCreateMenu: () => (
        <Menu.Item
          data-testid="workspace.library.header.create.knowledge"
          icon={<IconCozKnowledge />}
          onClick={openCreateKnowledgeModal}
        >
          {I18n.t('library_resource_type_knowledge')}
        </Menu.Item>
      ),
      target: [ResType.Knowledge],
      onItemClick: (item: ResourceInfo) => {
        navigate(`/space/${spaceId}/knowledge/${item.res_id}?from=library`);
      },
      renderItem: item => (
        <BaseLibraryItem
          resourceInfo={item}
          defaultIcon={DocDefaultIcon}
          tag={
            <>
              {safeJSONParse(item.biz_extend?.processing_file_id_list)?.length ? (
                <Tag
                  data-testid="workspace.library.item.tag"
                  color="brand"
                  size="mini"
                  className="flex-shrink-0 flex-grow-0"
                  prefixIcon={<IconCozClock />}
                >
                  {I18n.t('library_filter_tags_processing')}
                </Tag>
              ) : null}
              {item.res_sub_type !== undefined &&
              knowledgeSubTypeTextMap[item.res_sub_type] ? (
                <Tag
                  data-testid="workspace.library.item.tag"
                  color="brand"
                  size="mini"
                  className="flex-shrink-0 flex-grow-0"
                >
                  {I18n.t(knowledgeSubTypeTextMap[item.res_sub_type])}
                </Tag>
              ) : null}
            </>
          }
        />
      ),
      renderActions: (item: ResourceInfo) => {
        const deleteDisabled = !item.actions?.find(
          action => action.key === ActionKey.Delete,
        )?.enable;

        const deleteProps = {
          disabled: deleteDisabled,
          deleteDesc: I18n.t('library_delete_desc'),
          handler: () => {
            delKnowledge(item.res_id || '');
          },
        };

        return (
          <TableAction
            deleteProps={deleteProps}
            actionList={getCommonActions?.(item) ?? []}
          />
        );
      },
    },
  };
};

5. 知识库配置弹窗(useCreateKnowledgeModalV2)

文件位置:frontend/packages/data/knowledge/knowledge-modal-adapter/src/create-knowledge-modal-v2/scenes/base/index.tsx

知识库创建的主要Hook和界面:

typescript 复制代码
import { useRef, useState } from 'react';

import { useDataModalWithCoze } from '@coze-data/utils';
import { useDataNavigate } from '@coze-data/knowledge-stores';
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
import {
  CozeKnowledgeAddTypeContent,
  type CozeKnowledgeAddTypeContentFormData,
} from '@coze-data/knowledge-modal-base/create-knowledge-modal-v2';
import { KnowledgeE2e } from '@coze-data/e2e';
import { I18n } from '@coze-arch/i18n';
import { Button, Form, LoadingButton } from '@coze-arch/coze-design';
import { useSpaceStore } from '@coze-arch/bot-studio-store';
import { FormatType } from '@coze-arch/bot-api/knowledge';
import { KnowledgeApi } from '@coze-arch/bot-api';

export interface UseCreateKnowledgeModalParams {
  projectID?: string;
  onFinish?: (datasetId: string, type: UnitType, shouldUpload: boolean) => void;
  beforeCreate?: (shouldUpload: boolean) => void;
}

export const useCreateKnowledgeModalV2 = (
  params: UseCreateKnowledgeModalParams = {},
) => {
  const { onFinish, beforeCreate, projectID } = params;
  const formRef = useRef<Form<CozeKnowledgeAddTypeContentFormData>>(null);
  const [currentFormatType, setCurrentFormatType] = useState(FormatType.Text);
  const spaceId = useSpaceStore(store => store.getSpaceId());
  const resourceNavigate = useDataNavigate();
  const [unitType, setUnitType] = useState<UnitType>(UnitType.TEXT_DOC);

  const createDataset = async () => {
    await formRef.current?.formApi.validate();
    const { dataset_id: datasetId } = await KnowledgeApi.CreateDataset({
      project_id: projectID || undefined,
      name: formRef.current?.formApi.getValue('name'),
      format_type: currentFormatType,
      description: formRef.current?.formApi.getValue('description'),
      icon_uri: formRef.current?.formApi.getValue('icon_uri')?.[0].uid,
      space_id: spaceId || undefined,
    });
    return datasetId;
  };

  const { open, close, modal } = useDataModalWithCoze({
    title: (
      <div data-testid={KnowledgeE2e.CreateKnowledgeModalTitle}>
        {I18n.t('datasets_model_create_title')}
      </div>
    ),
    centered: true,
    onCancel: () => {
      close();
    },
    footer: (
      <div className="flex w-full justify-end">
        <Button
          color="primary"
          onClick={() => {
            close();
          }}
        >
          {I18n.t('cancel')}
        </Button>
        <LoadingButton
          color="primary"
          onClick={async () => {
            beforeCreate?.(false);
            const datasetId = await createDataset();
            if (onFinish) {
              onFinish(datasetId || '', unitType, false);
            } else {
              resourceNavigate.toResource?.('knowledge', datasetId);
            }
          }}
        >
          {I18n.t('kl_write_108')}
        </LoadingButton>
        <LoadingButton
          data-testid={KnowledgeE2e.CreateKnowledgeModalSubmitAndImportButton}
          color="primary"
          onClick={async () => {
            beforeCreate?.(true);
            const datasetId = await createDataset();
            if (onFinish) {
              onFinish(datasetId || '', unitType, true);
            } else {
              resourceNavigate.upload?.({ type: unitType });
            }
          }}
        >
          {I18n.t('kl_write_109')}
        </LoadingButton>
      </div>
    ),
  });

  return {
    modal: modal(
      <Form<CozeKnowledgeAddTypeContentFormData>
        ref={formRef}
        showValidateIcon={false}
      >
        <CozeKnowledgeAddTypeContent
          onImportKnowledgeTypeChange={setUnitType}
          onSelectFormatTypeChange={setCurrentFormatType}
        />
      </Form>,
    ),
    open: () => {
      setCurrentFormatType(FormatType.Text);
      open();
    },
    close,
  };
};
  

设计亮点

  • 状态集中管理 :通过 useCreateKnowledgeModalV2 Hook统一管理知识库创建状态
  • 组件解耦:各子组件职责明确,通过props进行通信
  • 数据流清晰:单向数据流,状态变更可追踪
  • 用户体验优化:支持两种创建模式(仅创建/创建并导入)
  • 表单验证完善:支持表单验证和实时反馈

6. 知识库表单组件(CozeKnowledgeAddTypeContent)

文件位置:frontend/packages/data/knowledge/knowledge-modal-base/src/create-knowledge-modal-v2/features/add-type-content/coze-knowledge/index.tsx

知识库创建表单的核心组件:

typescript 复制代码
import { useEffect, useState } from 'react';

import { CozeFormTextArea, CozeInputWithCountField } from '@coze-data/utils';
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
import { KnowledgeE2e } from '@coze-data/e2e';
import { PictureUpload } from '@coze-common/biz-components/picture-upload';
import { I18n } from '@coze-arch/i18n';
import { FormatType } from '@coze-arch/bot-api/knowledge';
import { type Icon } from '@coze-arch/bot-api/knowledge';
import { FileBizType, IconType } from '@coze-arch/bot-api/developer_api';
import { KnowledgeApi } from '@coze-arch/bot-api';
import { useFormApi } from '@coze-arch/coze-design';

export interface CozeKnowledgeAddTypeContentFormData {
  name: string;
  icon_uri?: Array<{
    url: string;
    uri: string;
    uid: string;
    isDefault?: boolean;
  }>;
  format_type: FormatType;
  description: string;
}

export const CozeKnowledgeAddTypeContent = (params: AddTypeContentProps) => {
  const { onImportKnowledgeTypeChange, onSelectFormatTypeChange } = params;
  const formApi = useFormApi<CozeKnowledgeAddTypeContentFormData>();
  const [currentFormatType, setCurrentFormatType] = useState(FormatType.Text);
  const [iconInfoGenerate, setIconInfoGenerate] = useState<{
    name: string;
    desc: string;
  }>({
    name: '',
    desc: '',
  });
  const [coverIcon, setCoverIcon] = useState<Icon | undefined>({
    uri: '',
    url: '',
  });

  const fetchIcon = async (formatType: FormatType) => {
    const { icon } = await KnowledgeApi.GetIcon({
      format_type: formatType,
    });
    setCoverIcon(icon);
    const currentCover = formApi.getValue('icon_uri');
    if (!currentCover || currentCover[0]?.isDefault) {
      formApi.setValue('icon_uri', [
        {
          url: icon?.url ?? '',
          uri: icon?.uri ?? '',
          uid: icon?.uri ?? '',
          isDefault: true,
        },
      ]);
    }
  };

  const [unitType, setUnitType] = useState<UnitType>(UnitType.TEXT_DOC);

  useEffect(() => {
    fetchIcon(currentFormatType);
    if (currentFormatType === FormatType.Text) {
      setUnitType(UnitType.TEXT_DOC);
    } else if (currentFormatType === FormatType.Table) {
      setUnitType(UnitType.TABLE_DOC);
    } else if (currentFormatType === FormatType.Image) {
      setUnitType(UnitType.IMAGE_FILE);
    }
  }, [currentFormatType]);

  return (
    <div data-testid={KnowledgeE2e.CreateKnowledgeModal}>
      <SelectFormatType
        field="format_type"
        noLabel
        onChange={(type: FormatType) => {
          setCurrentFormatType(type);
          formApi.setValue('format_type', type);
          onSelectFormatTypeChange?.(type);
        }}
      />
      <CozeInputWithCountField
        data-testid={KnowledgeE2e.CreateKnowledgeModalNameInput}
        field="name"
        label={I18n.t('datasets_model_create_name')}
        maxLength={100}
        rules={[
          {
            required: true,
            whitespace: true,
            message: I18n.t('dataset-name-empty-tooltip'),
          },
          {
            pattern: /^[^"'`\\]+$/,
            message: I18n.t('dataset-name-has-wrong-word-tooltip'),
          },
        ]}
        placeholder={I18n.t('datasets_model_create_name_placeholder')}
      />
      <CozeFormTextArea
        field="description"
        data-testid={KnowledgeE2e.CreateKnowledgeModalDescInput}
        label={I18n.t('datasets_model_create_description')}
        autosize={{ minRows: 1, maxRows: 2 }}
        maxCount={2000}
        maxLength={2000}
        placeholder={I18n.t('datasets_model_create_description_placeholder')}
      />
      <ImportKnowledgeSourceSelect
        formatType={currentFormatType}
        initValue={unitType}
        onChange={setUnitType}
      />
      <PictureUpload
        label={I18n.t('datasets_model_create_avatar')}
        field="icon_uri"
        testId={KnowledgeE2e.CreateKnowledgeModalAvatarUploader}
        fileBizType={FileBizType.BIZ_DATASET_ICON}
        iconType={IconType.Dataset}
        generateInfo={iconInfoGenerate}
      />
    </div>
  );
};

设计亮点

  • 多格式支持:支持文本、表格、图片三种知识库格式类型
  • 智能图标生成:根据知识库名称和描述自动生成图标
  • 表单验证完善:支持名称格式验证和字符长度限制
  • 数据源选择:支持多种数据导入类型选择
  • 用户体验优化:支持实时预览和智能提示
相关推荐
Ticnix1 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人1 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl1 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人1 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼2 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端
布列瑟农的星空2 小时前
前端都能看懂的Rust入门教程(三)——控制流语句
前端·后端·rust
Mr Xu_2 小时前
Vue 3 中计算属性的最佳实践:提升可读性、可维护性与性能
前端·javascript
jerrywus2 小时前
我写了个 Claude Code Skill,再也不用手动切图传 COS 了
前端·agent·claude
玖月晴空2 小时前
探索关于Spec 和Skills 的一些实战运用-Kiro篇
前端·aigc·代码规范