rsf-admin/src/page/system/aiParam/AiParamCreate.jsx
@@ -1,175 +1,13 @@
import React from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    SaveButton,
    SelectInput,
    Toolbar,
    useNotify,
    Form,
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Stack,
    Grid,
    Box,
} from '@mui/material';
import DialogCloseButton from "@/page/components/DialogCloseButton";
import StatusSelectInput from "@/page/components/StatusSelectInput";
import MemoInput from "@/page/components/MemoInput";
import { Create, SimpleForm } from "react-admin";
import AiParamForm from "./AiParamForm";
const yesNoChoices = [
    { id: 1, name: 'common.enums.true' },
    { id: 0, name: 'common.enums.false' },
];
const providerChoices = [
    { id: 'openai', name: 'OpenAI Compatible' },
    { id: 'mock', name: 'Mock' },
];
const AiParamCreate = (props) => {
    const { open, setOpen } = props;
    const translate = useTranslate();
    const notify = useNotify();
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
        }
    };
    const handleSuccess = async () => {
        setOpen(false);
        notify('common.response.success');
    };
    const handleError = async (error) => {
        notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
    };
    return (
        <CreateBase
            record={{ defaultFlag: 0, sort: 0, maxContextMessages: 12, status: 1, provider: 'openai' }}
            transform={(data) => {
                return data;
            }}
            mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
        >
            <Dialog
                open={open}
                onClose={handleClose}
                aria-labelledby="form-dialog-title"
                fullWidth
                disableRestoreFocus
                maxWidth="md"
            >
                <Form>
                    <DialogTitle id="form-dialog-title" sx={{
                        position: 'sticky',
                        top: 0,
                        backgroundColor: 'background.paper',
                        zIndex: 1000
                    }}
                    >
                        {translate('create.title')}
                        <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                            <DialogCloseButton onClose={handleClose} />
                        </Box>
                    </DialogTitle>
                    <DialogContent sx={{ mt: 2 }}>
                        <Grid container rowSpacing={2} columnSpacing={2}>
                            <Grid item xs={6} display="flex" gap={1}>
                                <TextInput label="table.field.aiParam.name" source="name" parse={v => v} fullWidth />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <TextInput label="table.field.aiParam.modelCode" source="modelCode" parse={v => v} fullWidth />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <SelectInput
                                    label="table.field.aiParam.provider"
                                    source="provider"
                                    choices={providerChoices}
                                    fullWidth
                                />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <TextInput
                                    label="table.field.aiParam.modelName"
                                    source="modelName"
                                    parse={v => v}
                                    helperText="填写真实模型名,例如 gpt-4o-mini、deepseek-chat"
                                    fullWidth
                                />
                            </Grid>
                            <Grid item xs={12} display="flex" gap={1}>
                                <TextInput
                                    label="table.field.aiParam.chatUrl"
                                    source="chatUrl"
                                    parse={v => v}
                                    helperText="支持填写 baseUrl,如 https://api.openai.com 或 https://api.siliconflow.cn,系统会自动补全为 /v1/chat/completions"
                                    fullWidth
                                />
                            </Grid>
                            <Grid item xs={12} display="flex" gap={1}>
                                <TextInput
                                    label="table.field.aiParam.apiKey"
                                    source="apiKey"
                                    parse={v => v}
                                    type="password"
                                    helperText="OpenAI 接口模式下填写 Bearer Token,无需手动加 Bearer 前缀"
                                    fullWidth
                                />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <NumberInput label="table.field.aiParam.maxContextMessages" source="maxContextMessages" fullWidth />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <NumberInput label="table.field.aiParam.sort" source="sort" fullWidth />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <SelectInput
                                    label="table.field.aiParam.defaultFlag"
                                    source="defaultFlag"
                                    choices={yesNoChoices}
                                    fullWidth
                                />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <StatusSelectInput fullWidth />
                            </Grid>
                            <Grid item xs={12} display="flex" gap={1}>
                                <TextInput
                                    label="table.field.aiParam.systemPrompt"
                                    source="systemPrompt"
                                    parse={v => v}
                                    fullWidth
                                    multiline
                                    minRows={4}
                                />
                            </Grid>
                            <Grid item xs={12} display="flex" gap={1}>
                                <Stack direction="column" spacing={1} width={'100%'}>
                                    <MemoInput />
                                </Stack>
                            </Grid>
                        </Grid>
                    </DialogContent>
                    <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                        <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
                            <SaveButton />
                        </Toolbar>
                    </DialogActions>
                </Form>
            </Dialog>
        </CreateBase>
    )
}
const AiParamCreate = () => (
    <Create redirect="list">
        <SimpleForm defaultValues={{ providerType: "OPENAI_COMPATIBLE", temperature: 0.7, topP: 1, timeoutMs: 60000, streamingEnabled: true, status: 1 }}>
            <AiParamForm />
        </SimpleForm>
    </Create>
);
export default AiParamCreate;