From 7a00868dc7730b83dc1e3d232b9f2e2b43ad237a Mon Sep 17 00:00:00 2001
From: vincentlu <t1341870251@gmail.com>
Date: 星期五, 07 二月 2025 14:51:29 +0800
Subject: [PATCH] #

---
 /dev/null                                                                                     |  261 --------------
 rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/UserLoginServiceImpl.java |    1 
 rsf-admin/src/page/login/index.jsx                                                            |  247 ++++---------
 rsf-admin/src/page/login/Register.jsx                                                         |  161 ++++++++
 rsf-admin/src/page/login/index2.jsx                                                           |  195 ++++++++++
 rsf-admin/src/i18n/zh.js                                                                      |    1 
 rsf-admin/src/page/login/Login.jsx                                                            |  159 ++++++++
 rsf-admin/src/i18n/en.js                                                                      |    1 
 rsf-admin/src/App.jsx                                                                         |    2 
 9 files changed, 599 insertions(+), 429 deletions(-)

diff --git a/rsf-admin/src/App.jsx b/rsf-admin/src/App.jsx
index 6d3a10a..00924d9 100644
--- a/rsf-admin/src/App.jsx
+++ b/rsf-admin/src/App.jsx
@@ -16,7 +16,7 @@
 import DataProvider from "./config/dataProvider";
 import Dashboard from "./page/dashboard/Dashboard";
 import Settings from "./page/settings/Settings";
-import Login from "./page/login/index1";
+import Login from "./page/login";
 import * as Common from './utils/common'
 import { themes } from './themes/themes';
 import { SPA_NAME, SPA_VERSION, DEFAULT_THEME_NAME, DEFAULT_THEME_MODE, DATA_PROVIDER_SPRING } from "./config/setting";
diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js
index 7dae7d3..fe4509a 100644
--- a/rsf-admin/src/i18n/en.js
+++ b/rsf-admin/src/i18n/en.js
@@ -223,6 +223,7 @@
             tenant: 'Tenant',
             button: {
                 login: 'LOG IN',
+                register: 'REGISTER',
             },
         },
     }
diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js
index bf5b646..016d04c 100644
--- a/rsf-admin/src/i18n/zh.js
+++ b/rsf-admin/src/i18n/zh.js
@@ -223,6 +223,7 @@
             tenant: '绉熸埛',
             button: {
                 login: 'LOG IN',
+                register: 'REGISTER',
             },
         },
     }
diff --git a/rsf-admin/src/page/login/Login.jsx b/rsf-admin/src/page/login/Login.jsx
new file mode 100644
index 0000000..e30af97
--- /dev/null
+++ b/rsf-admin/src/page/login/Login.jsx
@@ -0,0 +1,159 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import { useLocation } from 'react-router-dom';
+import {
+    Box,
+    CircularProgress,
+    Typography,
+    Button,
+    TextField,
+    Stack,
+    Autocomplete
+} from '@mui/material';
+import {
+    useTranslate,
+    useLogin,
+    useNotify,
+} from 'react-admin';
+import { useForm, Controller } from 'react-hook-form';
+
+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 username = watch('username');
+    const password = watch('password');
+    const tenantId = watch('tenantId');
+
+    useEffect(() => {
+        if (tenantList.length > 0 && !tenantId) {
+            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) => {
+                                        onChange(newValue ? newValue.id : '');
+                                    }}
+                                    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
+                            />
+                        )}
+                    />
+
+                    <Controller
+                        name="password"
+                        control={control}
+                        defaultValue=""
+                        rules={{ required: true }}
+                        render={({ field }) => (
+                            <TextField
+                                {...field}
+                                label={translate('ra.auth.password')}
+                                type="password"
+                                variant="standard"
+                                disabled={loading}
+
+                            />
+                        )}
+                    />
+
+                    <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>
+            </Box >
+        </>
+    )
+}
+
+export default Login;
\ No newline at end of file
diff --git a/rsf-admin/src/page/login/Register.jsx b/rsf-admin/src/page/login/Register.jsx
new file mode 100644
index 0000000..832081f
--- /dev/null
+++ b/rsf-admin/src/page/login/Register.jsx
@@ -0,0 +1,161 @@
+import React, { useState, useRef, useEffect, useMemo } from "react";
+import { useLocation } from 'react-router-dom';
+import {
+    Box,
+    CircularProgress,
+    Typography,
+    Button,
+    TextField,
+    Stack,
+    Autocomplete
+} from '@mui/material';
+import {
+    useTranslate,
+    useLogin,
+    useNotify,
+} from 'react-admin';
+import { useForm, Controller } from 'react-hook-form';
+
+const Register = (props) => {
+    const translate = useTranslate();
+    const notify = useNotify();
+    const login = useLogin();
+    const location = useLocation();
+    const { tab, tenantList } = props;
+
+    const { control, watch, handleSubmit, setValue } = useForm();
+
+    const [loading, setLoading] = useState(false);
+
+    const username = watch('username');
+    const password = watch('password');
+    const tenantId = watch('tenantId');
+
+    useEffect(() => {
+        if (tenantList.length > 0 && !tenantId) {
+            setValue('tenantId', tenantList[0].id);
+        }
+    }, [tenantList, setValue]);
+
+    const onSubmit = (data) => {
+        console.log(data);
+        setLoading(true);
+        // js native confirm && root
+        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) => {
+                                        onChange(newValue ? newValue.id : '');
+                                    }}
+                                    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
+                            />
+                        )}
+                    />
+
+                    <Controller
+                        name="password"
+                        control={control}
+                        defaultValue=""
+                        rules={{ required: true }}
+                        render={({ field }) => (
+                            <TextField
+                                {...field}
+                                label={translate('ra.auth.password')}
+                                type="password"
+                                variant="standard"
+                                disabled={loading}
+
+                            />
+                        )}
+                    />
+
+                    <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.register')}
+                    </Button>
+
+                </Stack>
+                <Box mt={1} mb={1} sx={{ textAlign: 'center' }}>or</Box>
+            </Box >
+        </>
+    )
+}
+
+export default Register;
\ No newline at end of file
diff --git a/rsf-admin/src/page/login/index.jsx b/rsf-admin/src/page/login/index.jsx
index 634211a..5c56eaf 100644
--- a/rsf-admin/src/page/login/index.jsx
+++ b/rsf-admin/src/page/login/index.jsx
@@ -1,195 +1,108 @@
-import * as React from 'react';
-import { useState } from 'react';
-import { useLocation } from 'react-router-dom';
+import React, { useState, useRef, useEffect, useMemo } from "react";
 import {
-    Avatar,
     Box,
-    Button,
+    AppBar,
     Card,
-    CardActions,
+    Toolbar,
     CircularProgress,
+    Typography,
+    Tabs,
+    Tab,
 } from '@mui/material';
-import LockIcon from '@mui/icons-material/Lock';
 import {
-    Form,
-    required,
-    TextInput,
     useTranslate,
     useLogin,
     useNotify,
-    SelectInput,
 } from 'react-admin';
 import { LOGIN_BACKGROUND } from '@/config/setting';
 import { tenants } from '@/api/auth';
+import Login from "./Login";
+import Register from "./Register";
 
-const Login = () => {
-    const [loading, setLoading] = useState(false);
+const Index = () => {
     const translate = useTranslate();
 
-    const notify = useNotify();
-    const login = useLogin();
-    const location = useLocation();
+    const [tab, setTab] = useState(0)
+    const [tenantList, setTenantList] = useState([]);
 
-    const [tenantList, setTenantList] = React.useState([]);
-    const [tenantId, setTenantId] = React.useState(null);
-
-    React.useEffect(() => {
+    useEffect(() => {
         tenants().then(data => {
             setTenantList(data);
-            if (data.length > 0) {
-                setTenantId(data[0].id);
-            }
         })
     }, []);
 
-    React.useEffect(() => {
-        console.log(tenantId);
-    }, [tenantId]);
-
-    const handleSubmit = (auth) => {
-        setLoading(true);
-        // js native confirm && root
-        login(
-            auth,
-            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 (
-        <Form onSubmit={handleSubmit} noValidate>
-            {/* https://unsplash.com/ */}
-            <Box
-                sx={{
-                    display: 'flex',
-                    flexDirection: 'column',
-                    minHeight: '100vh',
-                    alignItems: 'center',
-                    justifyContent: 'flex-start',
-                    // justifyContent: 'center',
-                    background: `url(/login_bg.jpg)`,
-                    backgroundRepeat: 'no-repeat',
-                    backgroundSize: 'cover',
+        <Box
+            sx={{
+                display: 'flex',
+                flexDirection: 'column',
+                minHeight: '100vh',
+                alignItems: 'center',
+                justifyContent: 'flex-start',
+                // justifyContent: 'center',
+                background: `url(/login_bg.jpg)`, // https://unsplash.com/
+                backgroundRepeat: 'no-repeat',
+                backgroundSize: 'cover',
+            }
+            }
+        >
+            <video
+                autoPlay
+                loop
+                muted
+                style={{
+                    position: 'fixed',
+                    top: 0,
+                    left: 0,
+                    width: '100%',
+                    height: '100%',
+                    // objectFit: 'cover',
+                    // objectFit: 'contain',
+                    objectFit: 'fill',
+                    // objectFit: 'scale-down',
+                    zIndex: 0,
                 }}
             >
-                <video
-                    autoPlay
-                    loop
-                    muted
-                    style={{
-                        position: 'fixed',
-                        top: 0,
-                        left: 0,
-                        width: '100%',
-                        height: '100%',
-                        // objectFit: 'cover',
-                        // objectFit: 'contain',
-                        objectFit: 'fill',
-                        // objectFit: 'scale-down',
-                        zIndex: 0,
-                    }}
-                >
-                    {LOGIN_BACKGROUND === 'media' && (
-                        <source src="/login_bg.mp4" type="video/mp4" />
-                    )}
-                </video>
+                {LOGIN_BACKGROUND === 'media' && (
+                    <source src="/login_bg.mp4" type="video/mp4" />
+                )}
+            </video>
 
-                <Card sx={{
-                    minWidth: 300,
-                    marginTop: '6em',
-                    zIndex: 1
-                }}>
-                    <Box
-                        sx={{
-                            margin: '1em',
-                            display: 'flex',
-                            justifyContent: 'center',
-                        }}
-                    >
-                        <Avatar sx={{ bgcolor: 'secondary.main' }}>
-                            <LockIcon />
-                        </Avatar>
-                    </Box>
-                    <Box
-                        sx={{
-                            marginTop: '1em',
-                            display: 'flex',
-                            justifyContent: 'center',
-                            color: theme => theme.palette.grey[500],
-                        }}
-                    >
-                        Hint: root / 123456
-                    </Box>
-                    <Box sx={{ padding: '0 1em 1em 1em' }}>
-                        <Box sx={{ marginTop: '1em' }}>
-                            <SelectInput
-                                label="page.login.tenant"
-                                source="tenantId"
-                                choices={tenantList.map(item => ({
-                                    id: item.id,
-                                    name: item.name
-                                }))}
-                                validate={required()}
-                                value={tenantId}
-                                onChange={e => setTenantId(e.target.value)}
-                            />
-                        </Box>
-                        <Box sx={{ marginTop: '.1em' }}>
-                            <TextInput
-                                autoFocus
-                                source="username"
-                                label={translate('ra.auth.username')}
-                                disabled={loading}
-                                validate={required()}
-                            />
-                        </Box>
-                        <Box sx={{ marginTop: '.1em' }}>
-                            <TextInput
-                                source="password"
-                                label={translate('ra.auth.password')}
-                                type="password"
-                                disabled={loading}
-                                validate={required()}
-                            />
-                        </Box>
-                    </Box>
-                    <CardActions sx={{ padding: '0 1em 1em 1em' }}>
-                        <Button
-                            variant="contained"
-                            type="submit"
-                            color="primary"
-                            disabled={loading}
-                            fullWidth
-                        >
-                            {loading && (
-                                <CircularProgress size={25} thickness={2} />
-                            )}
-                            {translate('ra.auth.sign_in')}
-                        </Button>
-                    </CardActions>
-                </Card>
-            </Box>
-        </Form>
+            <Card sx={{
+                width: 400,
+                marginTop: '6em',
+                zIndex: 1
+            }}>
+                <div>
+                    <AppBar position="static" sx={{ backgroundColor: '#3D4BA7' }}>
+                        <Toolbar>
+                            <Typography variant="h6" color="inherit">Welcome</Typography>
+                        </Toolbar>
+                    </AppBar>
+                </div>
+
+                <Tabs
+                    value={tab}
+                    onChange={(event, value) => {
+                        setTab(value);
+                    }}
+                    indicatorColor="primary"
+                    textColor="primary"
+                    variant="fullWidth"
+                >
+                    <Tab label="Login" sx={{ fontSize: '.8em' }} />
+                    <Tab label="Register" sx={{ fontSize: '.8em' }} />
+                </Tabs>
+
+                {tab === 0 && <Login tenantList={tenantList} />}
+                {tab === 1 && <Register tenantList={tenantList} />}
+
+                <Box mt={1} mb={1} sx={{ textAlign: 'center' }}>
+                    <Typography variant="caption" align="center">rsf - sever</Typography>
+                </Box>
+            </Card>
+        </Box >
     );
 };
 
-export default Login;
+export default Index;
diff --git a/rsf-admin/src/page/login/index1.jsx b/rsf-admin/src/page/login/index1.jsx
deleted file mode 100644
index bd9ff5e..0000000
--- a/rsf-admin/src/page/login/index1.jsx
+++ /dev/null
@@ -1,261 +0,0 @@
-import React, { useState, useRef, useEffect, useMemo } from "react";
-import { useLocation } from 'react-router-dom';
-import {
-    Box,
-    AppBar,
-    Card,
-    Toolbar,
-    CircularProgress,
-    Typography,
-    Tabs,
-    Tab,
-    Button
-} from '@mui/material';
-import {
-    Form,
-    required,
-    TextInput,
-    useTranslate,
-    useLogin,
-    useNotify,
-    SelectInput,
-} from 'react-admin';
-import { useForm, Controller } from 'react-hook-form';
-import { LOGIN_BACKGROUND } from '@/config/setting';
-import { tenants } from '@/api/auth';
-
-const Login = () => {
-    const translate = useTranslate();
-
-    const [tab, setTab] = useState(0)
-
-    const [tenantList, setTenantList] = useState([]);
-
-    useEffect(() => {
-        tenants().then(data => {
-            setTenantList(data);
-        })
-    }, []);
-
-    return (
-        <Box
-            sx={{
-                display: 'flex',
-                flexDirection: 'column',
-                minHeight: '100vh',
-                alignItems: 'center',
-                justifyContent: 'flex-start',
-                // justifyContent: 'center',
-                background: `url(/login_bg.jpg)`, // https://unsplash.com/
-                backgroundRepeat: 'no-repeat',
-                backgroundSize: 'cover',
-            }
-            }
-        >
-            <video
-                autoPlay
-                loop
-                muted
-                style={{
-                    position: 'fixed',
-                    top: 0,
-                    left: 0,
-                    width: '100%',
-                    height: '100%',
-                    // objectFit: 'cover',
-                    // objectFit: 'contain',
-                    objectFit: 'fill',
-                    // objectFit: 'scale-down',
-                    zIndex: 0,
-                }}
-            >
-                {LOGIN_BACKGROUND === 'media' && (
-                    <source src="/login_bg.mp4" type="video/mp4" />
-                )}
-            </video>
-
-            <Card sx={{
-                width: 400,
-                marginTop: '6em',
-                zIndex: 1
-            }}>
-                <div>
-                    <AppBar position="static" sx={{ backgroundColor: '#3D4BA7' }}>
-                        <Toolbar>
-                            <Typography variant="h6" color="inherit">Welcome</Typography>
-                        </Toolbar>
-                    </AppBar>
-                </div>
-
-                <Tabs
-                    value={tab}
-                    onChange={(event, value) => {
-                        setTab(value);
-                    }}
-                    indicatorColor="primary"
-                    textColor="primary"
-                    variant="fullWidth"
-                >
-                    <Tab label="Login" sx={{ fontSize: '.8em' }} />
-                    <Tab label="Register" sx={{ fontSize: '.8em' }} />
-                </Tabs>
-
-                <LoginForm
-                    tab={tab}
-                    tenantList={tenantList}
-                />
-
-                <RegisterForm
-                    tab={tab}
-                    tenantList={tenantList}
-                />
-
-                <Box mt={1} mb={1} sx={{ textAlign: 'center' }}>
-                    <Typography variant="caption" align="center">rsf - sever</Typography>
-                </Box>
-            </Card>
-        </Box >
-    );
-};
-
-const LoginForm = (props) => {
-    const translate = useTranslate();
-    const notify = useNotify();
-    const login = useLogin();
-    const location = useLocation();
-
-    const { tab, tenantList } = props;
-
-    const [loading, setLoading] = useState(false);
-    const [tenantId, setTenantId] = useState(null);
-    const [username, setUsername] = useState('');
-    const [password, setPassword] = useState('');
-    const [btnDisable, setBtnDisable] = useState(true);
-
-    useEffect(() => {
-        if (tenantList.length > 0) {
-            setTenantId(tenantList[0].id);
-        }
-        setBtnDisable(!(tenantId && username && password))
-    }, [tenantList, username, password]);
-
-    const handleSubmit = (auth) => {
-        console.log(auth);
-
-        setLoading(true);
-        // js native confirm && root
-        login(
-            auth,
-            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,
-                    },
-                }
-            );
-
-            setUsername(auth.username)
-        });
-    };
-
-    return (
-        <>
-            <Form
-                onSubmit={handleSubmit}
-                noValidate
-            >
-                <Box
-                    hidden={tab !== 0}
-                    p={2}
-                    display="flex"
-                    justifyContent="center"
-                    flexDirection='column'
-                >
-                    <Box width="60%">
-                        <SelectInput
-                            label="page.login.tenant"
-                            source="tenantId"
-                            variant="standard"
-                            choices={tenantList.map(item => ({
-                                id: item.id,
-                                name: item.name
-                            }))}
-                            validate={required()}
-                            defaultValue={tenantId}
-                            onChange={e => setTenantId(e.target.value)}
-                            sx={{ marginTop: 0, marginBottom: 0 }}
-                        />
-                    </Box>
-
-                    <TextInput
-                        label={translate('ra.auth.username')}
-                        source="username"
-                        variant="standard"
-                        disabled={loading}
-                        validate={required()}
-                        value={username}
-                        onChange={e => setUsername(e.target.value)}
-                        autoFocus
-                        sx={{ marginTop: 0, marginBottom: 0 }}
-                    />
-                    <TextInput
-                        label={translate('ra.auth.password')}
-                        source="password"
-                        variant="standard"
-                        type="password"
-                        disabled={loading}
-                        validate={required()}
-                        value={password}
-                        onChange={e => setPassword(e.target.value)}
-                        sx={{ marginTop: 0, marginBottom: 0 }}
-                    />
-                    <Button
-                        variant="contained"
-                        type="submit"
-                        disabled={loading || btnDisable}
-                        fullWidth
-                        sx={{
-                            backgroundColor: "#3D4BA7"
-                        }}
-                    >
-                        {loading && (
-                            <CircularProgress size={25} thickness={2} />
-                        )}
-                        {translate('page.login.button.login')}
-                    </Button>
-
-                    <Box mt={1} mb={1} sx={{ textAlign: 'center' }}>or</Box>
-                </Box >
-            </Form>
-        </>
-    )
-}
-
-const RegisterForm = (props) => {
-
-    return (
-        <>
-            <Box
-                hidden={props.tab !== 1}
-            >
-                Register
-            </Box >
-        </>
-    )
-}
-
-export default Login;
diff --git a/rsf-admin/src/page/login/index2.jsx b/rsf-admin/src/page/login/index2.jsx
new file mode 100644
index 0000000..634211a
--- /dev/null
+++ b/rsf-admin/src/page/login/index2.jsx
@@ -0,0 +1,195 @@
+import * as React from 'react';
+import { useState } from 'react';
+import { useLocation } from 'react-router-dom';
+import {
+    Avatar,
+    Box,
+    Button,
+    Card,
+    CardActions,
+    CircularProgress,
+} from '@mui/material';
+import LockIcon from '@mui/icons-material/Lock';
+import {
+    Form,
+    required,
+    TextInput,
+    useTranslate,
+    useLogin,
+    useNotify,
+    SelectInput,
+} from 'react-admin';
+import { LOGIN_BACKGROUND } from '@/config/setting';
+import { tenants } from '@/api/auth';
+
+const Login = () => {
+    const [loading, setLoading] = useState(false);
+    const translate = useTranslate();
+
+    const notify = useNotify();
+    const login = useLogin();
+    const location = useLocation();
+
+    const [tenantList, setTenantList] = React.useState([]);
+    const [tenantId, setTenantId] = React.useState(null);
+
+    React.useEffect(() => {
+        tenants().then(data => {
+            setTenantList(data);
+            if (data.length > 0) {
+                setTenantId(data[0].id);
+            }
+        })
+    }, []);
+
+    React.useEffect(() => {
+        console.log(tenantId);
+    }, [tenantId]);
+
+    const handleSubmit = (auth) => {
+        setLoading(true);
+        // js native confirm && root
+        login(
+            auth,
+            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 (
+        <Form onSubmit={handleSubmit} noValidate>
+            {/* https://unsplash.com/ */}
+            <Box
+                sx={{
+                    display: 'flex',
+                    flexDirection: 'column',
+                    minHeight: '100vh',
+                    alignItems: 'center',
+                    justifyContent: 'flex-start',
+                    // justifyContent: 'center',
+                    background: `url(/login_bg.jpg)`,
+                    backgroundRepeat: 'no-repeat',
+                    backgroundSize: 'cover',
+                }}
+            >
+                <video
+                    autoPlay
+                    loop
+                    muted
+                    style={{
+                        position: 'fixed',
+                        top: 0,
+                        left: 0,
+                        width: '100%',
+                        height: '100%',
+                        // objectFit: 'cover',
+                        // objectFit: 'contain',
+                        objectFit: 'fill',
+                        // objectFit: 'scale-down',
+                        zIndex: 0,
+                    }}
+                >
+                    {LOGIN_BACKGROUND === 'media' && (
+                        <source src="/login_bg.mp4" type="video/mp4" />
+                    )}
+                </video>
+
+                <Card sx={{
+                    minWidth: 300,
+                    marginTop: '6em',
+                    zIndex: 1
+                }}>
+                    <Box
+                        sx={{
+                            margin: '1em',
+                            display: 'flex',
+                            justifyContent: 'center',
+                        }}
+                    >
+                        <Avatar sx={{ bgcolor: 'secondary.main' }}>
+                            <LockIcon />
+                        </Avatar>
+                    </Box>
+                    <Box
+                        sx={{
+                            marginTop: '1em',
+                            display: 'flex',
+                            justifyContent: 'center',
+                            color: theme => theme.palette.grey[500],
+                        }}
+                    >
+                        Hint: root / 123456
+                    </Box>
+                    <Box sx={{ padding: '0 1em 1em 1em' }}>
+                        <Box sx={{ marginTop: '1em' }}>
+                            <SelectInput
+                                label="page.login.tenant"
+                                source="tenantId"
+                                choices={tenantList.map(item => ({
+                                    id: item.id,
+                                    name: item.name
+                                }))}
+                                validate={required()}
+                                value={tenantId}
+                                onChange={e => setTenantId(e.target.value)}
+                            />
+                        </Box>
+                        <Box sx={{ marginTop: '.1em' }}>
+                            <TextInput
+                                autoFocus
+                                source="username"
+                                label={translate('ra.auth.username')}
+                                disabled={loading}
+                                validate={required()}
+                            />
+                        </Box>
+                        <Box sx={{ marginTop: '.1em' }}>
+                            <TextInput
+                                source="password"
+                                label={translate('ra.auth.password')}
+                                type="password"
+                                disabled={loading}
+                                validate={required()}
+                            />
+                        </Box>
+                    </Box>
+                    <CardActions sx={{ padding: '0 1em 1em 1em' }}>
+                        <Button
+                            variant="contained"
+                            type="submit"
+                            color="primary"
+                            disabled={loading}
+                            fullWidth
+                        >
+                            {loading && (
+                                <CircularProgress size={25} thickness={2} />
+                            )}
+                            {translate('ra.auth.sign_in')}
+                        </Button>
+                    </CardActions>
+                </Card>
+            </Box>
+        </Form>
+    );
+};
+
+export default Login;
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/UserLoginServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/UserLoginServiceImpl.java
index 3d7b485..a2bc7c8 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/UserLoginServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/UserLoginServiceImpl.java
@@ -23,6 +23,7 @@
         userLogin.setUserId(userId);
         userLogin.setToken(token);
         userLogin.setType(type);
+        userLogin.setTenantId(tenantId);
         userLogin.setIp(IpTools.gainRealIp(request));
         userLogin.setMemo(memo);
         baseMapper.insert(userLogin);

--
Gitblit v1.9.1