Files
TERES_web_frontend/src/pages/knowledge/components/GeneralForm.tsx

214 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useRef } from 'react';
import { useFormContext, Controller, type UseFormReturn } from 'react-hook-form';
import {
Box,
Typography,
TextField,
FormControl,
InputLabel,
Select,
MenuItem,
Grid,
Avatar,
Button,
IconButton,
} from '@mui/material';
import {
PhotoCamera as PhotoCameraIcon,
Delete as DeleteIcon,
} from '@mui/icons-material';
interface GeneralFormProps {
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 handleAvatarUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file && form) {
const reader = new FileReader();
reader.onload = (e) => {
form.setValue('avatar', e.target?.result as string);
};
reader.readAsDataURL(file);
}
};
const handleAvatarDelete = () => {
if (form) {
form.setValue('avatar', undefined);
}
};
const handleAvatarClick = () => {
fileInputRef.current?.click();
};
const avatar = watch('avatar', '');
return (
<Box sx={{ p: 3 }}>
<Typography variant="h6" gutterBottom>
</Typography>
<Grid container spacing={3}>
<Grid size={{xs:12, md:6}}>
<Box sx={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 2 }}>
<Avatar
src={avatar}
sx={{ width: 120, height: 120, cursor: 'pointer' }}
onClick={handleAvatarClick}
>
{!avatar && <PhotoCameraIcon sx={{ fontSize: 40 }} />}
</Avatar>
<Box sx={{ display: 'flex', gap: 1 }}>
<Button
variant="outlined"
size="small"
startIcon={<PhotoCameraIcon />}
onClick={handleAvatarClick}
>
</Button>
{avatar && (
<IconButton
size="small"
color="error"
onClick={handleAvatarDelete}
>
<DeleteIcon />
</IconButton>
)}
</Box>
<input
ref={fileInputRef}
type="file"
accept="image/*"
style={{ display: 'none' }}
onChange={handleAvatarUpload}
/>
</Box>
</Grid>
{/* 表单字段 */}
<Grid size={{xs:12,md:8}}>
<Grid container spacing={2}>
<Grid size={{xs:12}}>
<Controller
name="name"
control={control}
rules={{ required: '知识库名称不能为空' }}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
label="知识库名称"
fullWidth
required
error={!!error}
helperText={error?.message}
/>
)}
/>
</Grid>
<Grid size={{xs:12}}>
<Controller
name="description"
control={control}
render={({ field }) => (
<TextField
{...field}
label="描述"
fullWidth
multiline
rows={3}
placeholder="请输入知识库描述..."
/>
)}
/>
</Grid>
<Grid size={{xs:12}}>
<Controller
name="permission"
control={control}
render={({ field }) => (
<FormControl fullWidth>
<InputLabel></InputLabel>
<Select {...field} label="权限设置">
<MenuItem value="me"></MenuItem>
<MenuItem value="team"></MenuItem>
</Select>
</FormControl>
)}
/>
</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>
);
}
export default GeneralForm;