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>
  );
};

设计亮点

  • 多格式支持:支持文本、表格、图片三种知识库格式类型
  • 智能图标生成:根据知识库名称和描述自动生成图标
  • 表单验证完善:支持名称格式验证和字符长度限制
  • 数据源选择:支持多种数据导入类型选择
  • 用户体验优化:支持实时预览和智能提示
相关推荐
百思可瑞教育3 小时前
在Vue项目中Axios发起请求时的小知识
前端·javascript·vue.js·北京百思教育
患得患失9493 小时前
【个人项目】【前端实用工具】OpenAPI to TypeScript 转换器
前端·javascript·typescript
大前端helloworld3 小时前
前端梳理体系从常问问题去完善-基础篇(html,css,js,ts)
前端·javascript·面试
trsoliu3 小时前
前端基于 TypeScript 使用 Mastra 来开发一个 AI 应用 / AI 代理(Agent)
前端·人工智能
鸡吃丸子3 小时前
前端权限控制:深入理解与实现RBAC模型
前端
Larry_zhang双栖3 小时前
低版本Chrome 内核兼容性问题的优美解决
前端·chrome
qq_12498707534 小时前
基于node.js+vue的医院陪诊系统的设计与实现(源码+论文+部署+安装)
前端·vue.js·node.js·毕业设计
袁煦丞4 小时前
9.12 Halo的“傻瓜建站魔法”:cpolar内网穿透实验室第637个成功挑战
前端·程序员·远程工作
universe_015 小时前
day27|前端框架学习
前端·笔记