feat(knowledge): refactor knowledge creation form and improve form handling
This commit is contained in:
4
.env
4
.env
@@ -1,5 +1,5 @@
|
|||||||
# VITE_API_BASE_URL = http://150.158.121.95
|
VITE_API_BASE_URL = http://150.158.121.95
|
||||||
VITE_API_BASE_URL = http://154.9.253.114:9380
|
# VITE_API_BASE_URL = http://154.9.253.114:9380
|
||||||
|
|
||||||
VITE_RSA_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
|
VITE_RSA_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB
|
||||||
|
|||||||
@@ -272,7 +272,9 @@ export const useKnowledgeOperations = () => {
|
|||||||
* 更新知识库基础信息
|
* 更新知识库基础信息
|
||||||
* 包括名称、描述、语言等基本信息
|
* 包括名称、描述、语言等基本信息
|
||||||
*/
|
*/
|
||||||
const updateKnowledgeBasicInfo = useCallback(async (data: IKnowledge) => {
|
const updateKnowledgeBasicInfo = useCallback(async (data: {
|
||||||
|
kb_id: string;
|
||||||
|
} & Partial<IKnowledge>) => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
@@ -300,10 +302,7 @@ export const useKnowledgeOperations = () => {
|
|||||||
*/
|
*/
|
||||||
const updateKnowledgeModelConfig = useCallback(async (data: {
|
const updateKnowledgeModelConfig = useCallback(async (data: {
|
||||||
kb_id: string;
|
kb_id: string;
|
||||||
embd_id?: string;
|
} & Partial<IKnowledge>) => {
|
||||||
parser_config?: Partial<IParserConfig>;
|
|
||||||
parser_id?: string;
|
|
||||||
}) => {
|
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useFormContext, useWatch } from 'react-hook-form';
|
import { useFormContext, useWatch, type UseFormReturn } from 'react-hook-form';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Typography,
|
Typography,
|
||||||
|
Button,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { DOCUMENT_PARSER_TYPES, type DocumentParserType } from '@/constants/knowledge';
|
import { DOCUMENT_PARSER_TYPES, type DocumentParserType } from '@/constants/knowledge';
|
||||||
import { type IParserConfig } from '@/interfaces/database/knowledge';
|
import { type IParserConfig } from '@/interfaces/database/knowledge';
|
||||||
@@ -59,8 +60,45 @@ export interface ConfigFormData extends IParserConfig {
|
|||||||
parser_id: DocumentParserType;
|
parser_id: DocumentParserType;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ChunkMethodForm() {
|
interface ChunkMethodFormProps {
|
||||||
const { control } = useFormContext();
|
form?: UseFormReturn;
|
||||||
|
onSubmit?: (data: any) => void;
|
||||||
|
isSubmitting?: boolean;
|
||||||
|
onCancel?: () => void;
|
||||||
|
submitButtonText?: string;
|
||||||
|
cancelButtonText?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ChunkMethodForm({
|
||||||
|
form: propForm,
|
||||||
|
onSubmit,
|
||||||
|
isSubmitting,
|
||||||
|
onCancel,
|
||||||
|
submitButtonText = '保存',
|
||||||
|
cancelButtonText = '取消',
|
||||||
|
}: ChunkMethodFormProps = {}) {
|
||||||
|
// 优先使用props传递的form,否则使用FormProvider的context
|
||||||
|
let contextForm;
|
||||||
|
try {
|
||||||
|
contextForm = useFormContext();
|
||||||
|
} catch (error) {
|
||||||
|
contextForm = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = propForm || contextForm;
|
||||||
|
|
||||||
|
if (!form) {
|
||||||
|
console.error('ChunkMethodForm: No form context found. Component must be used within a FormProvider or receive a form prop.');
|
||||||
|
return (
|
||||||
|
<Box sx={{ p: 2, textAlign: 'center' }}>
|
||||||
|
<Typography color="error">
|
||||||
|
表单配置错误:请确保组件在FormProvider中使用或传递form参数
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { control } = form;
|
||||||
|
|
||||||
// 监听parser_id变化
|
// 监听parser_id变化
|
||||||
const parser_id = useWatch({
|
const parser_id = useWatch({
|
||||||
@@ -79,6 +117,28 @@ function ChunkMethodForm() {
|
|||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
|
||||||
{/* 动态配置内容 */}
|
{/* 动态配置内容 */}
|
||||||
<ConfigurationComponent />
|
<ConfigurationComponent />
|
||||||
|
|
||||||
|
{/* 表单操作按钮 - 仅在有onSubmit回调时显示 */}
|
||||||
|
{onSubmit && (
|
||||||
|
<Box sx={{ mt: 4, display: 'flex', justifyContent: 'flex-end', gap: 2 }}>
|
||||||
|
{onCancel && (
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={onCancel}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{cancelButtonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={form ? form.handleSubmit(onSubmit) : undefined}
|
||||||
|
disabled={isSubmitting || !form}
|
||||||
|
>
|
||||||
|
{isSubmitting ? '提交中...' : submitButtonText}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { useFormContext, Controller } from 'react-hook-form';
|
import { useFormContext, Controller, type UseFormReturn } from 'react-hook-form';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Typography,
|
Typography,
|
||||||
@@ -18,30 +18,69 @@ import {
|
|||||||
Delete as DeleteIcon,
|
Delete as DeleteIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
|
|
||||||
function GeneralForm() {
|
interface GeneralFormProps {
|
||||||
const { control, watch, setValue } = useFormContext();
|
form?: UseFormReturn;
|
||||||
|
onSubmit?: (data: any) => void;
|
||||||
|
isSubmitting?: boolean;
|
||||||
|
onCancel?: () => void;
|
||||||
|
submitButtonText?: string;
|
||||||
|
cancelButtonText?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GeneralForm({
|
||||||
|
form: propForm,
|
||||||
|
onSubmit,
|
||||||
|
isSubmitting,
|
||||||
|
onCancel,
|
||||||
|
submitButtonText = '保存',
|
||||||
|
cancelButtonText = '取消',
|
||||||
|
}: GeneralFormProps = {}) {
|
||||||
|
// 优先使用props传递的form,否则使用FormProvider的context
|
||||||
|
let contextForm: UseFormReturn | null = null;
|
||||||
|
try {
|
||||||
|
contextForm = useFormContext();
|
||||||
|
} catch (error) {
|
||||||
|
contextForm = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = propForm || contextForm;
|
||||||
|
|
||||||
|
if (!form) {
|
||||||
|
console.error('GeneralForm: No form context found. Component must be used within a FormProvider or receive a form prop.');
|
||||||
|
return (
|
||||||
|
<Box sx={{ p: 2, textAlign: 'center' }}>
|
||||||
|
<Typography color="error">
|
||||||
|
表单配置错误:请确保组件在FormProvider中使用或传递form参数
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { control, watch, setValue, handleSubmit } = form;
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const handleAvatarUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleAvatarUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const file = event.target.files?.[0];
|
const file = event.target.files?.[0];
|
||||||
if (file) {
|
if (file && form) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
setValue('avatar', e.target?.result as string);
|
form.setValue('avatar', e.target?.result as string);
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAvatarDelete = () => {
|
const handleAvatarDelete = () => {
|
||||||
setValue('avatar', undefined);
|
if (form) {
|
||||||
|
form.setValue('avatar', undefined);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAvatarClick = () => {
|
const handleAvatarClick = () => {
|
||||||
fileInputRef.current?.click();
|
fileInputRef.current?.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
const avatar = watch('avatar');
|
const avatar = watch('avatar', '');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ p: 3 }}>
|
<Box sx={{ p: 3 }}>
|
||||||
@@ -146,6 +185,28 @@ function GeneralForm() {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
{/* 表单操作按钮 - 仅在有onSubmit回调时显示 */}
|
||||||
|
{onSubmit && (
|
||||||
|
<Box sx={{ mt: 4, display: 'flex', justifyContent: 'flex-end', gap: 2 }}>
|
||||||
|
{onCancel && (
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
onClick={onCancel}
|
||||||
|
disabled={isSubmitting}
|
||||||
|
>
|
||||||
|
{cancelButtonText}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={form ? form.handleSubmit(onSubmit) : undefined}
|
||||||
|
disabled={isSubmitting || !form}
|
||||||
|
>
|
||||||
|
{isSubmitting ? '提交中...' : submitButtonText}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useForm, type UseFormReturn } from 'react-hook-form';
|
import { useForm, FormProvider, useWatch, Form } from 'react-hook-form';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Typography,
|
Typography,
|
||||||
@@ -9,46 +9,29 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Alert,
|
Alert,
|
||||||
Divider,
|
Divider,
|
||||||
CircularProgress,
|
|
||||||
Stepper,
|
Stepper,
|
||||||
Step,
|
Step,
|
||||||
StepLabel,
|
StepLabel,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import {
|
import {
|
||||||
ArrowBack as ArrowBackIcon,
|
ArrowBack as ArrowBackIcon,
|
||||||
Settings as SettingsIcon,
|
|
||||||
CheckCircle as CheckCircleIcon,
|
CheckCircle as CheckCircleIcon,
|
||||||
SkipNext as SkipNextIcon,
|
SkipNext as SkipNextIcon,
|
||||||
} from '@mui/icons-material';
|
} from '@mui/icons-material';
|
||||||
import { useKnowledgeOperations } from '@/hooks/knowledge-hooks';
|
import { useKnowledgeOperations, useKnowledgeDetail } from '@/hooks/knowledge-hooks';
|
||||||
import GeneralForm from './components/GeneralForm';
|
import GeneralForm from './components/GeneralForm';
|
||||||
import ChunkMethodForm from './components/ChunkMethodForm';
|
import ChunkMethodForm from './components/ChunkMethodForm';
|
||||||
|
import { useSnackbar } from '@/components/Provider/SnackbarProvider';
|
||||||
|
import { DOCUMENT_PARSER_TYPES } from '@/constants/knowledge';
|
||||||
|
|
||||||
// 基础信息表单数据
|
// 统一表单数据类型
|
||||||
interface BasicFormData {
|
interface BaseFormData {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
permission: string;
|
permission: string;
|
||||||
avatar?: string;
|
avatar?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置表单数据
|
|
||||||
interface ConfigFormData {
|
|
||||||
parser_id: string;
|
|
||||||
embd_id?: string;
|
|
||||||
chunk_token_num?: number;
|
|
||||||
layout_recognize?: string;
|
|
||||||
delimiter?: string;
|
|
||||||
auto_keywords?: number;
|
|
||||||
auto_questions?: number;
|
|
||||||
html4excel?: boolean;
|
|
||||||
topn_tags?: number;
|
|
||||||
use_raptor?: boolean;
|
|
||||||
use_graphrag?: boolean;
|
|
||||||
graphrag_method?: string;
|
|
||||||
pagerank?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const steps = ['基础信息', '配置设置'];
|
const steps = ['基础信息', '配置设置'];
|
||||||
|
|
||||||
function KnowledgeBaseCreate() {
|
function KnowledgeBaseCreate() {
|
||||||
@@ -65,77 +48,111 @@ function KnowledgeBaseCreate() {
|
|||||||
clearError
|
clearError
|
||||||
} = useKnowledgeOperations();
|
} = useKnowledgeOperations();
|
||||||
|
|
||||||
// 基础信息表单
|
const { showMessage } = useSnackbar();
|
||||||
const basicForm = useForm<BasicFormData>({
|
|
||||||
|
// 获取知识库详情的hook
|
||||||
|
const { knowledge: knowledgeDetail, refresh: refreshKnowledgeDetail } = useKnowledgeDetail(createdKbId || '');
|
||||||
|
|
||||||
|
// 统一表单管理
|
||||||
|
const form = useForm<any>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
permission: 'me',
|
permission: 'me',
|
||||||
avatar: '',
|
avatar: undefined,
|
||||||
},
|
parser_id: DOCUMENT_PARSER_TYPES.Naive,
|
||||||
});
|
|
||||||
|
|
||||||
// 配置表单
|
|
||||||
const configForm = useForm<ConfigFormData>({
|
|
||||||
defaultValues: {
|
|
||||||
parser_id: 'naive',
|
|
||||||
embd_id: 'text-embedding-v3@Tongyi-Qianwen',
|
embd_id: 'text-embedding-v3@Tongyi-Qianwen',
|
||||||
|
parser_config: {
|
||||||
chunk_token_num: 512,
|
chunk_token_num: 512,
|
||||||
layout_recognize: 'DeepDOC',
|
|
||||||
delimiter: '\n',
|
delimiter: '\n',
|
||||||
auto_keywords: 0,
|
auto_keywords: 0,
|
||||||
auto_questions: 0,
|
auto_questions: 0,
|
||||||
html4excel: false,
|
html4excel: false,
|
||||||
topn_tags: 10,
|
topn_tags: 10,
|
||||||
|
raptor: {
|
||||||
use_raptor: false,
|
use_raptor: false,
|
||||||
|
prompt: '请总结以下段落。小心数字,不要编造。段落如下:\n {cluster_content}\n以上就是你需要总结的内容。',
|
||||||
|
max_token: 256,
|
||||||
|
threshold: 0.1,
|
||||||
|
max_cluster: 64,
|
||||||
|
random_seed: 0,
|
||||||
|
},
|
||||||
|
graphrag: {
|
||||||
use_graphrag: false,
|
use_graphrag: false,
|
||||||
graphrag_method: 'light',
|
entity_types: ['organization', 'person', 'geo', 'event', 'category'],
|
||||||
pagerank: 0.3,
|
method: 'light',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理基础信息提交
|
// 处理表单提交
|
||||||
const handleBasicSubmit = async (data: BasicFormData) => {
|
const handleSubmit = async ({ data }: { data: any }) => {
|
||||||
clearError();
|
clearError();
|
||||||
|
console.log('提交数据:', data);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await createKnowledge(data);
|
if (activeStep === 0) {
|
||||||
setCreatedKbId(result.kb_id);
|
// 第一步:创建知识库基础信息
|
||||||
setActiveStep(1);
|
const basicData = {
|
||||||
} catch (err) {
|
name: data.name,
|
||||||
console.error('创建知识库失败:', err);
|
description: data.description,
|
||||||
}
|
permission: data.permission,
|
||||||
|
avatar: data.avatar,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理配置提交
|
const result = await createKnowledge(basicData);
|
||||||
const handleConfigSubmit = async (data: ConfigFormData) => {
|
setCreatedKbId(result.kb_id);
|
||||||
|
|
||||||
|
// 获取创建后的知识库详情,确保获取到正确的名称
|
||||||
|
setTimeout(async () => {
|
||||||
|
await refreshKnowledgeDetail();
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
setActiveStep(1);
|
||||||
|
showMessage.success('知识库创建成功,请配置解析设置');
|
||||||
|
} else {
|
||||||
|
// 第二步:配置知识库解析设置
|
||||||
if (!createdKbId) return;
|
if (!createdKbId) return;
|
||||||
|
|
||||||
clearError();
|
// 使用知识库详情中的正确名称,如果没有则使用表单中的名称
|
||||||
|
const correctName = knowledgeDetail?.name || data.name;
|
||||||
|
|
||||||
try {
|
const configData = {
|
||||||
await updateKnowledgeModelConfig({
|
kb_id: createdKbId,
|
||||||
id: createdKbId,
|
name: correctName, // 使用正确的名称
|
||||||
...data,
|
description: data.description,
|
||||||
});
|
permission: data.permission,
|
||||||
|
avatar: data.avatar,
|
||||||
|
parser_id: data.parser_id,
|
||||||
|
embd_id: data.embd_id,
|
||||||
|
parser_config: data.parser_config,
|
||||||
|
};
|
||||||
|
|
||||||
|
await updateKnowledgeModelConfig(configData);
|
||||||
|
showMessage.success('知识库配置完成');
|
||||||
navigate('/knowledge');
|
navigate('/knowledge');
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('配置知识库失败:', err);
|
console.error('操作失败:', err);
|
||||||
|
showMessage.error(activeStep === 0 ? '创建知识库失败' : '配置知识库失败');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// 跳过配置
|
|
||||||
const handleSkipConfig = () => {
|
|
||||||
navigate('/knowledge');
|
|
||||||
};
|
|
||||||
|
|
||||||
// 返回上一步
|
// 跳过配置,直接完成创建
|
||||||
const handleBack = () => {
|
const handleSkipConfig = async () => {
|
||||||
setActiveStep(0);
|
try {
|
||||||
|
showMessage.success('知识库创建完成,您可以稍后在设置页面配置解析参数');
|
||||||
|
navigate('/knowledge');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('跳过配置失败:', err);
|
||||||
|
showMessage.error('操作失败');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ maxWidth: 800, mx: 'auto', p: 3 }}>
|
<Box sx={{ p: 3 }}>
|
||||||
{/* 页面标题 */}
|
{/* 页面头部 */}
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3 }}>
|
||||||
<Button
|
<Button
|
||||||
startIcon={<ArrowBackIcon />}
|
startIcon={<ArrowBackIcon />}
|
||||||
@@ -150,13 +167,17 @@ function KnowledgeBaseCreate() {
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* 步骤指示器 */}
|
{/* 步骤指示器 */}
|
||||||
<Stepper activeStep={activeStep} sx={{ mb: 4 }}>
|
<Card sx={{ mb: 3 }}>
|
||||||
|
<CardContent>
|
||||||
|
<Stepper activeStep={activeStep} alternativeLabel>
|
||||||
{steps.map((label) => (
|
{steps.map((label) => (
|
||||||
<Step key={label}>
|
<Step key={label}>
|
||||||
<StepLabel>{label}</StepLabel>
|
<StepLabel>{label}</StepLabel>
|
||||||
</Step>
|
</Step>
|
||||||
))}
|
))}
|
||||||
</Stepper>
|
</Stepper>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
{/* 错误提示 */}
|
{/* 错误提示 */}
|
||||||
{error && (
|
{error && (
|
||||||
@@ -165,22 +186,14 @@ function KnowledgeBaseCreate() {
|
|||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* 表单内容 */}
|
||||||
|
<FormProvider {...form}>
|
||||||
|
<Form onSubmit={handleSubmit}>
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{/* 第一步:基础信息 */}
|
{activeStep === 0 ? (
|
||||||
{activeStep === 0 && (
|
<GeneralForm form={form} />
|
||||||
<GeneralForm
|
) : (
|
||||||
form={basicForm}
|
|
||||||
onSubmit={handleBasicSubmit}
|
|
||||||
isSubmitting={isSubmitting}
|
|
||||||
onCancel={() => navigate('/knowledge')}
|
|
||||||
submitButtonText="下一步"
|
|
||||||
cancelButtonText="取消"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 第二步:配置设置 */}
|
|
||||||
{activeStep === 1 && (
|
|
||||||
<Box>
|
<Box>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
||||||
<CheckCircleIcon color="success" sx={{ mr: 1 }} />
|
<CheckCircleIcon color="success" sx={{ mr: 1 }} />
|
||||||
@@ -192,31 +205,60 @@ function KnowledgeBaseCreate() {
|
|||||||
您可以现在配置这些设置,也可以稍后在知识库详情页面中修改
|
您可以现在配置这些设置,也可以稍后在知识库详情页面中修改
|
||||||
</Typography>
|
</Typography>
|
||||||
<Divider sx={{ mb: 3 }} />
|
<Divider sx={{ mb: 3 }} />
|
||||||
|
<ChunkMethodForm form={form} />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
<ChunkMethodForm
|
<Divider sx={{ my: 3 }} />
|
||||||
form={configForm as any}
|
|
||||||
onSubmit={(data) => handleConfigSubmit(data as any)}
|
|
||||||
isSubmitting={isSubmitting}
|
|
||||||
onCancel={handleBack}
|
|
||||||
submitButtonText="完成配置"
|
|
||||||
cancelButtonText="返回上一步"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* 跳过配置按钮 */}
|
{/* 操作按钮 */}
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'center', mt: 2 }}>
|
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
|
||||||
|
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||||
|
{activeStep === 0 && (
|
||||||
<Button
|
<Button
|
||||||
variant="text"
|
variant="outlined"
|
||||||
startIcon={<SkipNextIcon />}
|
onClick={() => navigate('/knowledge')}
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 第二步显示跳过配置按钮 */}
|
||||||
|
{activeStep === 1 && (
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
onClick={handleSkipConfig}
|
onClick={handleSkipConfig}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
|
startIcon={<SkipNextIcon />}
|
||||||
>
|
>
|
||||||
跳过配置,稍后设置
|
跳过配置
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
variant="contained"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
startIcon={
|
||||||
|
activeStep === steps.length - 1 ? (
|
||||||
|
<CheckCircleIcon />
|
||||||
|
) : (
|
||||||
|
<SkipNextIcon />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{isSubmitting
|
||||||
|
? '处理中...'
|
||||||
|
: activeStep === steps.length - 1
|
||||||
|
? '完成创建'
|
||||||
|
: '下一步'}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
</Form>
|
||||||
|
</FormProvider>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user