From a19b70e1af79238c298ef8af6d0265bf6a22c92d Mon Sep 17 00:00:00 2001 From: vincentlu <t1341870251@gmail.com> Date: 星期五, 07 二月 2025 16:15:50 +0800 Subject: [PATCH] # --- rsf-admin/src/page/login/Login.jsx | 189 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 189 insertions(+), 0 deletions(-) diff --git a/rsf-admin/src/page/login/Login.jsx b/rsf-admin/src/page/login/Login.jsx new file mode 100644 index 0000000..c4e4825 --- /dev/null +++ b/rsf-admin/src/page/login/Login.jsx @@ -0,0 +1,189 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { useLocation } from 'react-router-dom'; +import { + Box, + CircularProgress, + Typography, + Button, + TextField, + Stack, + Autocomplete, + InputAdornment, + IconButton, +} from '@mui/material'; +import { + useTranslate, + useLogin, + useNotify, +} from 'react-admin'; +import { useForm, Controller } from 'react-hook-form'; +import ProviderChoices from "./ProviderChoices"; +import Visibility from '@mui/icons-material/Visibility'; +import VisibilityOff from '@mui/icons-material/VisibilityOff'; + +const Login = (props) => { + const translate = useTranslate(); + const notify = useNotify(); + const login = useLogin(); + const location = useLocation(); + const { tenantList } = props; + + const { control, watch, handleSubmit, setValue } = useForm(); + + const [loading, setLoading] = useState(false); + const [showPassword, setShowPassword] = useState(false); + + const username = watch('username'); + const password = watch('password'); + const tenantId = watch('tenantId'); + + useEffect(() => { + if (tenantList.length > 0 && !tenantId) { + const rememberTenantId = localStorage.getItem('remember_tenantId'); + if (rememberTenantId && tenantList.some(t => t.id === Number(rememberTenantId))) { + setValue('tenantId', Number(rememberTenantId)); + } else { + setValue('tenantId', tenantList[0].id); + } + } + }, [tenantList, setValue]); + + const onSubmit = (data) => { + setLoading(true); + login( + data, + location.state ? (location.state).nextPathname : '/' + ).catch((error) => { + setLoading(false); + notify( + typeof error === 'string' + ? error + : typeof error === 'undefined' || !error.message + ? 'ra.auth.sign_in_error' + : error.message, + { + type: 'error', + messageArgs: { + _: + typeof error === 'string' + ? error + : error && error.message + ? error.message + : undefined, + }, + } + ); + }); + }; + + return ( + <> + <Box + p={2} + display="flex" + flexDirection='column' + component="form" onSubmit={handleSubmit(onSubmit)} noValidate + > + <Stack spacing={2}> + <Controller + name="tenantId" + control={control} + rules={{ required: true }} + defaultValue={tenantList.length > 0 ? tenantList[0].id : ''} + render={({ field: { onChange, value, ref } }) => { + const selectedTenant = tenantList.find(tenant => tenant.id === value) || null; + return ( + <Autocomplete + options={tenantList} + getOptionLabel={(option) => option.name} + value={selectedTenant} + onChange={(_, newValue) => { + const newTenantId = newValue ? newValue.id : ''; + onChange(newTenantId); + localStorage.setItem('remember_tenantId', newTenantId); + }} + renderInput={(params) => ( + <TextField + {...params} + label={translate("page.login.tenant")} + variant="standard" + inputRef={ref} + /> + )} + /> + ); + }} + /> + + <Controller + name="username" + control={control} + defaultValue="" + rules={{ required: true }} + render={({ field }) => ( + <TextField + {...field} + label={translate('ra.auth.username')} + variant="standard" + disabled={loading} + autoFocus + autoComplete="off" + /> + )} + /> + + <Controller + name="password" + control={control} + defaultValue="" + rules={{ required: true }} + render={({ field }) => ( + <TextField + {...field} + label={translate('ra.auth.password')} + type={showPassword ? 'text' : 'password'} + variant="standard" + disabled={loading} + autoComplete="off" + 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> + ), + }} + /> + )} + /> + + <Box mt={10}></Box> + + <Button + type="submit" + variant="contained" + disabled={loading || !(tenantId && username && password)} + sx={{ + backgroundColor: "#3D4BA7" + }} + > + {loading && <CircularProgress size={25} thickness={2} />} + {translate('page.login.button.login')} + </Button> + + </Stack> + <Box mt={1} mb={1} sx={{ textAlign: 'center' }}>or</Box> + + <ProviderChoices type="LOG IN" /> + </Box > + </> + ) +} + +export default Login; \ No newline at end of file -- Gitblit v1.9.1