diff --git a/frontend/src/app/knowledge/(desktop)/features/CreateKnowledgeBase.tsx b/frontend/src/app/knowledge/(desktop)/features/CreateKnowledgeBase.tsx new file mode 100644 index 00000000..737274a0 --- /dev/null +++ b/frontend/src/app/knowledge/(desktop)/features/CreateKnowledgeBase.tsx @@ -0,0 +1,78 @@ +import { Modal, type ModalProps } from '@lobehub/ui'; +import { Form, Input, Select } from 'antd'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +// export const imageTypeOptions: SegmentedProps['options'] = [ +// { +// label: 'JPG', +// value: ImageType.JPG, +// }, +// { +// label: 'PNG', +// value: ImageType.PNG, +// }, +// { +// label: 'SVG', +// value: ImageType.SVG, +// }, +// { +// label: 'WEBP', +// value: ImageType.WEBP, +// }, +// ]; + +const DEFAULT_FIELD_VALUE = { + // imageType: ImageType.JPG, + withBackground: true, + withFooter: false, + withPluginInfo: false, + withSystemRole: false, +}; + +const CreateKnowledgeBase = memo(({ onClose, open }) => { + const { t } = useTranslation('chat'); + + return ( + +
+ + + + + + + +
+ + + +
+
+ + + +
+
+
+
+ ); +}); + +export default CreateKnowledgeBase; diff --git a/frontend/src/app/knowledge/(desktop)/features/KnowledgeConfig.tsx b/frontend/src/app/knowledge/(desktop)/features/KnowledgeConfig.tsx deleted file mode 100644 index e69de29b..00000000 diff --git a/frontend/src/app/knowledge/(desktop)/index.tsx b/frontend/src/app/knowledge/(desktop)/index.tsx index 5caf1ba3..1be83767 100644 --- a/frontend/src/app/knowledge/(desktop)/index.tsx +++ b/frontend/src/app/knowledge/(desktop)/index.tsx @@ -1,22 +1,38 @@ 'use client'; -import { memo } from 'react'; +import { FloatButton } from 'antd'; +import { Plus } from 'lucide-react'; +import dynamic from 'next/dynamic'; +import { memo, useEffect, useState } from 'react'; import { Flexbox } from 'react-layout-kit'; import ResponsiveIndex from '@/components/ResponsiveIndex'; import KnowledgeCardList from './features/KnowledgeList'; +// import CreateKnowledgeBase from './features/createKnowledgeBase'; import Layout from './layout.desktop'; +const CreateKnowledgeBase = dynamic(() => import('./features/CreateKnowledgeBase')); // const Mobile: FC = dynamic(() => import('../(mobile)'), { ssr: false }) as FC; -const DesktopPage = memo(() => ( -
321
}> - - - - - -
-)); +const DesktopPage = memo(() => { + const [showModal, setShowModal] = useState(false); + useEffect(() => { + setShowModal(true); + }, []); + const onClose = () => setShowModal(false); + return ( +
321
}> + + + + + + } onClick={() => setShowModal(true)}> + 新建知识库 + + +
+ ); +}); export default DesktopPage; diff --git a/frontend/src/app/knowledge/[id]/base/[fileId]/features/ModalSegment.tsx b/frontend/src/app/knowledge/[id]/base/[fileId]/features/ModalSegment.tsx new file mode 100644 index 00000000..c5521a4b --- /dev/null +++ b/frontend/src/app/knowledge/[id]/base/[fileId]/features/ModalSegment.tsx @@ -0,0 +1,17 @@ +import { Input, Modal } from 'antd'; +import { memo } from 'react'; +import { Center, Flexbox } from 'react-layout-kit'; + +const ModalSegment = memo(() => { + return ( + + +
+ +
+
+
+ ); +}); + +export default ModalSegment; diff --git a/frontend/src/app/knowledge/[id]/base/[fileId]/page.tsx b/frontend/src/app/knowledge/[id]/base/[fileId]/page.tsx new file mode 100644 index 00000000..f87c3248 --- /dev/null +++ b/frontend/src/app/knowledge/[id]/base/[fileId]/page.tsx @@ -0,0 +1,70 @@ +'use client'; + +import { Card, List } from 'antd'; +import { createStyles } from 'antd-style'; +import React, { memo, useState } from 'react'; + +import ModalSegment from './features/ModalSegment'; + +const data = [ + { + title: 'Title 1', + }, + { + title: 'Title 2', + }, + { + title: 'Title 3', + }, + { + title: 'Title 4', + }, + { + title: 'Title 5', + }, + { + title: 'Title 6', + }, +]; +const useStyle = createStyles(({ css, token }) => ({ + card: css` + cursor: pointer; + overflow: hidden; + &:hover { + box-shadow: 0 0 0 1px ${token.colorText}; + } + + &:active { + scale: 0.95; + } + `, +})); + +const App = memo(() => { + const { styles } = useStyle(); + const [isShowModal, setModal] = useState(); + return ( + <> + ( + + console.log(1)}> + Card content + + + )} + size="large" + /> + + + ); +}); + +export default App; diff --git a/frontend/src/app/knowledge/[id]/base/features/ModalAddFile.tsx b/frontend/src/app/knowledge/[id]/base/features/ModalAddFile.tsx new file mode 100644 index 00000000..37df8bec --- /dev/null +++ b/frontend/src/app/knowledge/[id]/base/features/ModalAddFile.tsx @@ -0,0 +1,45 @@ +import { InboxOutlined } from '@ant-design/icons'; +import type { UploadProps } from 'antd'; +import { Modal, Upload, message } from 'antd'; +import React, { memo } from 'react'; + +const { Dragger } = Upload; + +const props: UploadProps = { + action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload', + multiple: true, + name: 'file', + onChange(info) { + const { status } = info.file; + if (status !== 'uploading') { + console.log(info.file, info.fileList); + } + if (status === 'done') { + message.success(`${info.file.name} file uploaded successfully.`); + } else if (status === 'error') { + message.error(`${info.file.name} file upload failed.`); + } + }, + onDrop(e) { + console.log('Dropped files', e.dataTransfer.files); + }, +}; + +const ModalAddFile = memo(() => { + return ( + + +

+ +

+

Click or drag file to this area to upload

+

+ Support for a single or bulk upload. Strictly prohibited from uploading company data or + other banned files. +

+
+
+ ); +}); + +export default ModalAddFile; diff --git a/frontend/src/app/knowledge/[id]/base/page.tsx b/frontend/src/app/knowledge/[id]/base/page.tsx new file mode 100644 index 00000000..603e6625 --- /dev/null +++ b/frontend/src/app/knowledge/[id]/base/page.tsx @@ -0,0 +1,121 @@ +'use client'; + +import { Button, Table } from 'antd'; +import type { TableColumnsType } from 'antd'; +import React, { useState } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import ModalAddFile from './features/ModalAddFile'; + +interface DataType { + address: string; + age: number; + key: React.Key; + name: string; +} + +const columns: TableColumnsType = [ + { + dataIndex: 'index', + title: '序号', + }, + { + dataIndex: 'name', + title: '文档名称', + }, + { + dataIndex: 'loader', + title: '文档加载器', + }, + { + dataIndex: 'loader', + title: '文档加载器', + }, + { + dataIndex: 'splitter', + title: '分词器', + }, + { + dataIndex: 'source', + title: '源文件', + }, + { + dataIndex: 'vector', + title: '向量库', + }, +]; + +const data: DataType[] = []; +for (let i = 0; i < 46; i++) { + data.push({ + address: `London, Park Lane no. ${i}`, + age: 32, + key: i, + name: `Edward King ${i}`, + }); +} + +const App: React.FC = () => { + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const [loading, setLoading] = useState(false); + + const start = () => { + setLoading(true); + // ajax request after empty completing + setTimeout(() => { + setSelectedRowKeys([]); + setLoading(false); + }, 1000); + }; + + const onSelectChange = (newSelectedRowKeys: React.Key[]) => { + console.log('selectedRowKeys changed:', newSelectedRowKeys); + setSelectedRowKeys(newSelectedRowKeys); + }; + + const rowSelection = { + onChange: onSelectChange, + selectedRowKeys, + }; + const hasSelected = selectedRowKeys.length > 0; + + return ( + <> + + + + + + + + + {hasSelected ? `Selected ${selectedRowKeys.length} items` : ''} + + +
+ +
+
+ + + + + ); +}; + +export default App; diff --git a/frontend/src/app/knowledge/[id]/config/page.tsx b/frontend/src/app/knowledge/[id]/config/page.tsx new file mode 100644 index 00000000..6b607537 --- /dev/null +++ b/frontend/src/app/knowledge/[id]/config/page.tsx @@ -0,0 +1,62 @@ +'use client'; + +import { Form, type ItemGroup } from '@lobehub/ui'; +import { Form as AntForm, Input, InputNumber, Slider, Switch } from 'antd'; +import { Settings } from 'lucide-react'; +import { memo, useCallback } from 'react'; + +import { FORM_STYLE } from '@/const/layoutTokens'; + +const KnowledgeBaseConfig = memo(() => { + const [form] = AntForm.useForm(); + + const handleConfigChange = useCallback(() => { + console.log(321); + }, []); + const system: ItemGroup = { + children: [ + { + children: , + desc: '名称', + label: '知识库名称', + name: 'name', + }, + { + children: , + desc: '简介', + label: '知识库简介', + name: 'intro', + }, + { + children: , + desc: '321', + label: '单段文本最大长度', + name: 'paragraphMaxLength', + }, + { + children: , + desc: '321', + label: '相邻文本重合长度', + name: 'paragraphOverlapLength', + }, + { + children: , + desc: '321', + label: '文本匹配条数', + name: 'paragraphMatchCount', + }, + { + children: , + desc: '321', + label: '开启中文标题加强', + name: 'chineseTitleEnhance', + }, + ], + icon: Settings, + title: '知识库设置', + }; + + return
; +}); + +export default KnowledgeBaseConfig; diff --git a/frontend/src/app/knowledge/[id]/features/KnowledgeBaseConfig.tsx b/frontend/src/app/knowledge/[id]/features/KnowledgeBaseConfig.tsx new file mode 100644 index 00000000..2a7af4dd --- /dev/null +++ b/frontend/src/app/knowledge/[id]/features/KnowledgeBaseConfig.tsx @@ -0,0 +1,31 @@ +import { Form, type ItemGroup } from '@lobehub/ui'; +import { Form as AntForm, Input } from 'antd'; +import { AppWindow } from 'lucide-react'; +import { memo, useCallback } from 'react'; + +import { FORM_STYLE } from '@/const/layoutTokens'; + +// 参考settings/llm/Anthropic/index.tsx的代码生成一个名为KnowledgeBaseConfig.tsx的表单组件 +const KnowledgeBaseConfig = memo(() => { + const [form] = AntForm.useForm(); + + const handleConfigChange = useCallback(() => { + console.log(321); + }, []); + const system: ItemGroup = { + children: [ + { + children: , + desc: '知识库名称321', + label: '知识库名称', + name: 'password', + }, + ], + icon: AppWindow, + title: '321', + }; + + return ; +}); + +export default KnowledgeBaseConfig; diff --git a/frontend/src/app/knowledge/[id]/layout.tsx b/frontend/src/app/knowledge/[id]/layout.tsx new file mode 100644 index 00000000..e3efe0b4 --- /dev/null +++ b/frontend/src/app/knowledge/[id]/layout.tsx @@ -0,0 +1,43 @@ +'use client'; + +import { createStyles } from 'antd-style'; +import { PropsWithChildren, memo } from 'react'; +import { Center, Flexbox } from 'react-layout-kit'; + +import AppLayoutDesktop from '@/layout/AppLayout.desktop'; +import { SidebarTabKey } from '@/store/global/initialState'; + +import KnowledgeTabs from './tabs'; + +const useStyles = createStyles(({ stylish, token, css }) => ({ + container: { + paddingLeft: 20, + paddingRight: 20, + position: 'relative', + }, +})); + +export default memo(({ children, params }: PropsWithChildren) => { + console.log(params); + return ( + + + + +
图标占位
+
知识库名称
+
+ +
+ +
{children}
+
+
+
+ ); +}); diff --git a/frontend/src/app/knowledge/[id]/page.tsx b/frontend/src/app/knowledge/[id]/page.tsx new file mode 100644 index 00000000..bbf5adb9 --- /dev/null +++ b/frontend/src/app/knowledge/[id]/page.tsx @@ -0,0 +1,11 @@ +'use client'; + +import dynamic from 'next/dynamic'; +import { memo } from 'react'; + +const KnowledgeBaseConfig = dynamic(() => import('./features/KnowledgeBaseConfig')); +const KnowledgeDetail = memo(() => { + return ; +}); + +export default KnowledgeDetail; diff --git a/frontend/src/app/knowledge/[id]/tabs/TabItem.tsx b/frontend/src/app/knowledge/[id]/tabs/TabItem.tsx new file mode 100644 index 00000000..22fcd99a --- /dev/null +++ b/frontend/src/app/knowledge/[id]/tabs/TabItem.tsx @@ -0,0 +1,50 @@ +import { Icon, List } from '@lobehub/ui'; +import { createStyles, useResponsive } from 'antd-style'; +import { ChevronRight, type LucideIcon } from 'lucide-react'; +import { CSSProperties, ReactNode, memo } from 'react'; + +const { Item } = List; + +const useStyles = createStyles(({ css, token, responsive }) => ({ + container: css` + position: relative; + padding-top: 16px; + padding-bottom: 16px; + border-radius: ${token.borderRadius}px; + ${responsive.mobile} { + border-radius: 0; + } + `, + noHover: css` + pointer-events: none; + `, +})); + +export interface ItemProps { + active?: boolean; + className?: string; + hoverable?: boolean; + icon: LucideIcon; + label: ReactNode; + style?: CSSProperties; +} + +const KnowledgeTabItem = memo( + ({ label, icon, hoverable = true, active = false, style, className }) => { + const { cx, styles } = useStyles(); + const { mobile } = useResponsive(); + return ( + } + className={cx(styles.container, !hoverable && styles.noHover, className)} + style={style} + title={label as string} + > + {mobile && } + + ); + }, +); + +export default KnowledgeTabItem; diff --git a/frontend/src/app/knowledge/[id]/tabs/index.tsx b/frontend/src/app/knowledge/[id]/tabs/index.tsx new file mode 100644 index 00000000..9c036bee --- /dev/null +++ b/frontend/src/app/knowledge/[id]/tabs/index.tsx @@ -0,0 +1,28 @@ +import { Settings2, Webhook } from 'lucide-react'; +import Link from 'next/link'; +import { memo } from 'react'; + +import { KnowledgeTabs } from '@/store/global/initialState'; + +import Item from './TabItem'; + +export interface KnowledgeTabsProps { + activeTab?: KnowledgeTabs; + params: Record; +} + +const KnowledgeTabsBox = memo(({ activeTab, params }) => { + console.log(params); + const items = [ + { icon: Webhook, label: '知识库', value: KnowledgeTabs.Base }, + { icon: Settings2, label: '配置', value: KnowledgeTabs.Config }, + ]; + + return items.map(({ value, icon, label }) => ( + + + + )); +}); + +export default KnowledgeTabsBox; diff --git a/frontend/src/store/global/initialState.ts b/frontend/src/store/global/initialState.ts index 0494ffe9..00d70059 100644 --- a/frontend/src/store/global/initialState.ts +++ b/frontend/src/store/global/initialState.ts @@ -2,7 +2,7 @@ import { GlobalCommonState, initialCommonState } from './slices/common/initialSt import { GlobalPreferenceState, initialPreferenceState } from './slices/preference/initialState'; import { GlobalSettingsState, initialSettingsState } from './slices/settings/initialState'; -export { SettingsTabs, SidebarTabKey } from './slices/common/initialState'; +export { KnowledgeTabs, SettingsTabs, SidebarTabKey } from './slices/common/initialState'; export type GlobalState = GlobalCommonState & GlobalSettingsState & GlobalPreferenceState; diff --git a/frontend/src/store/global/slices/common/initialState.ts b/frontend/src/store/global/slices/common/initialState.ts index 77a9f0da..84540c7b 100644 --- a/frontend/src/store/global/slices/common/initialState.ts +++ b/frontend/src/store/global/slices/common/initialState.ts @@ -15,6 +15,11 @@ export enum SettingsTabs { TTS = 'tts', } +export enum KnowledgeTabs { + Base = 'base', + Config = 'config', +} + export interface Guide { // Topic 引导 topic?: boolean;