From 4d04f07390681995d7786ecb1730f4caea2e2f18 Mon Sep 17 00:00:00 2001
From: zjj <3272660260@qq.com>
Date: 星期六, 24 五月 2025 09:13:53 +0800
Subject: [PATCH] #移库
---
rsf-admin/src/page/login/Login.jsx | 297 ++++++++++++++++++++++++++++++++--------------------------
1 files changed, 164 insertions(+), 133 deletions(-)
diff --git a/rsf-admin/src/page/login/Login.jsx b/rsf-admin/src/page/login/Login.jsx
index f212d46..186f09a 100644
--- a/rsf-admin/src/page/login/Login.jsx
+++ b/rsf-admin/src/page/login/Login.jsx
@@ -1,164 +1,195 @@
-import * as React from 'react';
-import { useState } from 'react';
+import React, { useState, useRef, useEffect, useMemo } from "react";
import { useLocation } from 'react-router-dom';
import {
- Avatar,
Box,
- Button,
- Card,
- CardActions,
CircularProgress,
+ Typography,
+ Button,
+ TextField,
+ Stack,
+ Autocomplete,
+ InputAdornment,
+ IconButton,
} from '@mui/material';
-import LockIcon from '@mui/icons-material/Lock';
import {
- Form,
- required,
- TextInput,
useTranslate,
useLogin,
+ localStorageStore,
useNotify,
} from 'react-admin';
-import { LOGIN_BACKGROUND } from '@/config/setting';
+import { getSystemDicts } from "@/api/auth";
+import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
+import ProviderChoices from "./ProviderChoices";
+import Visibility from '@mui/icons-material/Visibility';
+import VisibilityOff from '@mui/icons-material/VisibilityOff';
-const Login = () => {
- const [loading, setLoading] = useState(false);
+const Login = (props) => {
const translate = useTranslate();
-
const notify = useNotify();
const login = useLogin();
const location = useLocation();
+ const { systemInfo: { mode }, tenantList } = props;
- const handleSubmit = (auth) => {
+ const { control, handleSubmit, watch, setValue, getValues, setError, clearErrors } = 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) => {
+ getSystemDicts().then(data => {
+ localStorage.setItem('sys_dicts', JSON.stringify(data));
+ })
setLoading(true);
- // js native confirm && root
login(
- auth,
+ data,
location.state ? (location.state).nextPathname : '/'
- ).catch((error) => {
+ ).catch((res) => {
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,
- },
- }
- );
+ const { code, msg, data } = res;
+ if (code === 10003) {
+ setError('username', {
+ message: msg
+ })
+ } else if (code === 10004) {
+ setError('username', {
+ message: msg
+ })
+ } else if (code === 10001) {
+ setError('password', {
+ message: msg
+ })
+ } else {
+ notify(msg, { type: 'error', messageArgs: { _: msg } });
+ }
});
};
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',
- }}
+ p={2}
+ display="flex"
+ flexDirection='column'
+ component="form" onSubmit={handleSubmit(onSubmit)} noValidate
>
- <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" />
+ <Stack spacing={2}>
+ {mode === 'OFFLINE' && (
+ <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}
+ />
+ )}
+ />
+ );
+ }}
+ />
)}
- </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' }}>
- <TextInput
+ <Controller
+ name="username"
+ control={control}
+ defaultValue=""
+ rules={{ required: true }}
+ render={({ field, fieldState: { error } }) => (
+ <TextField
+ {...field}
+ label={translate("page.login.username")}
+ variant="standard"
+ disabled={loading}
autoFocus
- source="username"
- label={translate('ra.auth.username')}
- disabled={loading}
- validate={required()}
+ autoComplete="off"
+ error={!!error}
+ helperText={error?.message || ""}
/>
- </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;
+ <Controller
+ name="password"
+ control={control}
+ defaultValue=""
+ rules={{ required: true }}
+ render={({ field, fieldState: { error } }) => (
+ <TextField
+ {...field}
+ label={translate("page.login.password")}
+ type={showPassword ? 'text' : 'password'}
+ variant="standard"
+ disabled={loading}
+ 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>
+ ),
+ }}
+ />
+ )}
+ />
+
+ <Box />
+
+ <Button
+ type="submit"
+ variant="contained"
+ disabled={loading || !((mode === 'OFFLINE' ? tenantId : true) && username && password)}
+ >
+ {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