From cbccc558b50020901b586d82d94a76be07c48c38 Mon Sep 17 00:00:00 2001
From: vincentlu <t1341870251@gmail.com>
Date: 星期二, 11 二月 2025 15:34:11 +0800
Subject: [PATCH] #
---
rsf-admin/src/page/tenant/TenantCreate.jsx | 415 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 336 insertions(+), 79 deletions(-)
diff --git a/rsf-admin/src/page/tenant/TenantCreate.jsx b/rsf-admin/src/page/tenant/TenantCreate.jsx
index 94dfa50..94013a4 100644
--- a/rsf-admin/src/page/tenant/TenantCreate.jsx
+++ b/rsf-admin/src/page/tenant/TenantCreate.jsx
@@ -1,19 +1,8 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
- CreateBase,
useTranslate,
- TextInput,
- NumberInput,
- BooleanInput,
- DateInput,
- SaveButton,
- SelectInput,
- Toolbar,
- required,
- useDataProvider,
useNotify,
- Form,
- useCreateController,
+ useRefresh,
} from 'react-admin';
import {
Dialog,
@@ -23,92 +12,360 @@
Stack,
Grid,
Box,
+ Stepper,
+ Step,
+ StepLabel,
+ StepContent,
+ Button,
+ TextField,
+ InputAdornment,
+ IconButton,
} from '@mui/material';
+import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
+import { matchPath, useLocation } from 'react-router';
import DialogCloseButton from "../components/DialogCloseButton";
-import StatusSelectInput from "../components/StatusSelectInput";
-import MemoInput from "../components/MemoInput";
+import Visibility from '@mui/icons-material/Visibility';
+import VisibilityOff from '@mui/icons-material/VisibilityOff';
+import request from '@/utils/request';
const TenantCreate = (props) => {
const { open, setOpen } = props;
-
const translate = useTranslate();
const notify = useNotify();
+ const refresh = useRefresh();
+ const {
+ control,
+ handleSubmit,
+ watch,
+ setValue,
+ getValues,
+ reset,
+ formState: {
+ errors,
+ isDirty,
+ },
+ trigger
+ } = useForm();
+
+ const passwordVal = watch('password');
+
+ const [activeStep, setActiveStep] = useState(0);
+ const [showPassword, setShowPassword] = useState(false);
+
+ const validateCurrentStep = async () => {
+ let fieldsToValidate = [];
+ if (activeStep === 0) {
+ fieldsToValidate = ['name', 'flag'];
+ } else if (activeStep === 1) {
+ fieldsToValidate = ['username', 'email', 'password', 'confirmPassword'];
+ } else if (activeStep === 2) {
+ fieldsToValidate = ['memo'];
+ }
+ return await trigger(fieldsToValidate);
+ };
+
+ const handleNext = async () => {
+ const isValid = await validateCurrentStep();
+ if (!isValid) {
+ return;
+ }
+ setActiveStep(prev => prev + 1);
+ };
+
+ const handleBack = () => {
+ setActiveStep(prev => prev - 1);
+ };
const handleClose = (event, reason) => {
if (reason !== "backdropClick") {
+ setActiveStep(0);
setOpen(false);
+ reset();
}
};
- const handleSuccess = async (data) => {
- setOpen(false);
- notify('common.response.success');
- };
-
- const handleError = async (error) => {
- notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
- };
+ const onSubmit = (data) => {
+ request.post('/tenant/init', data).then(res => {
+ const { code, msg, data } = res.data;
+ if (code === 200) {
+ notify(msg, { type: 'success', messageArgs: { _: msg } });
+ setOpen(false);
+ reset();
+ refresh();
+ } else {
+ notify(msg, { type: 'error', messageArgs: { _: msg } });
+ }
+ }).catch((error) => {
+ notify(error.message, { type: 'error', messageArgs: { _: error.message } });
+ console.error(error);
+ })
+ }
return (
<>
- <CreateBase
- record={{}}
- transform={(data) => {
- return data;
- }}
- mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
+ <Dialog
+ open={open}
+ onClose={handleClose}
+ aria-labelledby="form-dialog-title"
+ fullWidth
+ disableRestoreFocus
+ maxWidth="md" // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
>
- <Dialog
- open={open}
- onClose={handleClose}
- aria-labelledby="form-dialog-title"
- fullWidth
- disableRestoreFocus
- maxWidth="md" // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
- >
- <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>
- <Grid container rowSpacing={2} columnSpacing={2}>
- <Grid item xs={6} display="flex" gap={1}>
- <TextInput
- label="table.field.tenant.name"
- source="name"
- parse={v => v}
- autoFocus
- validate={required()}
- />
- </Grid>
+ <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 }}>
+ {open && (
+ <form noValidate onSubmit={handleSubmit(onSubmit)} >
+ <Stepper activeStep={activeStep} orientation="vertical">
+ <Step>
+ <StepLabel>{translate('page.tenant.create.title.basic')}</StepLabel>
+ <StepContent>
+ <Stack spacing={3} mt={2} direction='column' width={'50%'}>
+ <Controller
+ name="name"
+ control={control}
+ defaultValue=""
+ rules={{ required: true }}
+ parse={v => v}
+ render={({ field, fieldState: { error } }) => (
+ <TextField
+ {...field}
+ label={translate('table.field.tenant.name')}
+ variant="outlined"
+ autoComplete="off"
+ error={!!error}
+ helperText={error ? translate('ra.validation.required') : ""}
+ />
+ )}
+ />
+ <Controller
+ name="flag"
+ control={control}
+ defaultValue=""
+ rules={{
+ required: {
+ value: true,
+ message: translate('ra.validation.required')
+ },
+ pattern: {
+ value: /^[A-Za-z]{3,20}$/,
+ message: translate('page.tenant.create.tip.onlyEn'),
+ }
+ }}
+ parse={v => v}
+ render={({ field, fieldState: { error } }) => (
+ <TextField
+ {...field}
+ label={translate('table.field.tenant.flag')}
+ variant="outlined"
+ autoComplete="off"
+ error={!!error}
+ helperText={error ? error.message : ""}
+ />
+ )}
+ />
+ </Stack>
+ <Box sx={{ mt: 3 }}>
+ <Button onClick={handleNext} variant="contained">
+ {translate('page.tenant.create.btn.next')}
+ </Button>
+ <Button disabled={activeStep === 0} onClick={handleBack}>
+ {translate('page.tenant.create.btn.back')}
+ </Button>
+ </Box>
+ </StepContent>
+ </Step>
- <Grid item xs={6} display="flex" gap={1}>
- <StatusSelectInput />
- </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>
+ <Step>
+ <StepLabel>{translate('page.tenant.create.title.root')}</StepLabel>
+ <StepContent>
+ <Stack spacing={3} mt={2} direction='column' width={'50%'}>
+ <Controller
+ name="username"
+ control={control}
+ defaultValue=""
+ rules={{
+ required: {
+ value: true,
+ message: translate('ra.validation.required')
+ },
+ pattern: {
+ value: /^[A-Za-z0-9]{3,20}$/,
+ message: translate('page.settings.resetPwd.tip.usernameLimit'),
+ },
+ }}
+ parse={v => v}
+ render={({ field, fieldState: { error } }) => (
+ <TextField
+ {...field}
+ label={translate('table.field.user.username')}
+ variant="outlined"
+ autoComplete="off"
+ error={!!error}
+ helperText={error ? error.message : ""}
+ />
+ )}
+ />
+ <Controller
+ name="email"
+ control={control}
+ defaultValue=""
+ rules={{
+ required: false,
+ pattern: {
+ value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
+ message: translate("ra.validation.email"),
+ },
+ }}
+ render={({ field, fieldState: { error } }) => (
+ <TextField
+ {...field}
+ label={translate('table.field.user.email')}
+ variant="outlined"
+ autoComplete="off"
+ error={!!error}
+ helperText={error ? error.message : ""}
+ />
+ )}
+ />
+ <Controller
+ name="password"
+ control={control}
+ defaultValue=""
+ rules={{
+ required: {
+ value: true,
+ message: translate('ra.validation.required'),
+ },
+ pattern: {
+ value: /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d\.]{6,13}$/,
+ message: translate('page.settings.resetPwd.tip.pwdInputLimit'),
+ },
+ }}
+ render={({ field, fieldState: { error } }) => (
+ <TextField
+ {...field}
+ label={translate('page.settings.resetPwd.newPwd')}
+ type={showPassword ? 'text' : 'password'}
+ variant="outlined"
+ autoComplete="off"
+ error={!!error}
+ helperText={error ? error.message : ""}
+ InputProps={{
+ endAdornment: (
+ <InputAdornment position="end">
+ <IconButton
+ aria-label="toggle password visibility"
+ onClick={() => setShowPassword((show) => !show)}
+ onMouseDown={(event) => { event.preventDefault() }}
+ edge="end"
+ >
+ {showPassword ? <VisibilityOff /> : <Visibility />}
+ </IconButton>
+ </InputAdornment>
+ ),
+ }}
+ />
+ )}
+ />
+ <Controller
+ name="confirmPassword"
+ control={control}
+ defaultValue=""
+ rules={{
+ required: translate('ra.validation.required'),
+ validate: value =>
+ value === passwordVal || translate('page.settings.resetPwd.tip.pwdNotMatch'),
+ }}
+ render={({ field, fieldState: { error } }) => (
+ <TextField
+ {...field}
+ label={translate('page.settings.resetPwd.confirmNewPwd')}
+ type={showPassword ? 'text' : 'password'}
+ variant="outlined"
+ autoComplete="off"
+ error={!!error}
+ helperText={error?.message || ""}
+ InputProps={{
+ endAdornment: (
+ <InputAdornment position="end">
+ <IconButton
+ aria-label="toggle password visibility"
+ onClick={() => setShowPassword((show) => !show)}
+ onMouseDown={(event) => { event.preventDefault() }}
+ edge="end"
+ >
+ {showPassword ? <VisibilityOff /> : <Visibility />}
+ </IconButton>
+ </InputAdornment>
+ ),
+ }}
+ />
+ )}
+ />
+ </Stack>
+ <Box sx={{ mt: 3 }}>
+ <Button onClick={handleNext} variant="contained">
+ {translate('page.tenant.create.btn.next')}
+ </Button>
+ <Button onClick={handleBack}>
+ {translate('page.tenant.create.btn.back')}
+ </Button>
+ </Box>
+ </StepContent>
+ </Step>
+
+ <Step>
+ <StepLabel>{translate('page.tenant.create.title.confirm')}</StepLabel>
+ <StepContent>
+ <Stack spacing={3} mt={2} direction='column' width={'50%'}>
+ <Controller
+ name="memo"
+ control={control}
+ defaultValue=""
+ rules={{ required: false }}
+ parse={v => v}
+ render={({ field, fieldState: { error } }) => (
+ <TextField
+ {...field}
+ label={translate('common.field.memo')}
+ variant="outlined"
+ autoComplete="off"
+ fullWidth
+ multiline
+ minRows={2}
+ error={!!error}
+ helperText={error ? translate('ra.validation.required') : ""}
+ />
+ )}
+ />
+ </Stack>
+ <Box sx={{ mt: 3 }}>
+ <Button type="submit" variant="contained">
+ {translate('ra.action.save')}
+ </Button>
+ <Button onClick={handleBack}>
+ {translate('page.tenant.create.btn.back')}
+ </Button>
+ </Box>
+ </StepContent>
+ </Step>
+ </Stepper>
+ </form>
+ )}
+ </DialogContent>
+ <DialogActions sx={{ height: 10, position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
+ </DialogActions>
+ </Dialog>
</>
)
}
--
Gitblit v1.9.1