From 2fd817916072018b631c4f608c75ff455efb42a6 Mon Sep 17 00:00:00 2001 From: vincentlu <t1341870251@gmail.com> Date: 星期四, 13 二月 2025 16:36:11 +0800 Subject: [PATCH] # --- rsf-admin/src/page/login/Register.jsx | 173 ++++++++++++++++++++++++++++++++----------- rsf-admin/src/i18n/zh.js | 5 + rsf-admin/src/i18n/en.js | 3 3 files changed, 136 insertions(+), 45 deletions(-) diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js index d3640ec..808c6b5 100644 --- a/rsf-admin/src/i18n/en.js +++ b/rsf-admin/src/i18n/en.js @@ -229,9 +229,11 @@ title: 'Welcome', footer: 'Footer Goes Here', tenant: 'Company', + email: 'Email Address', username: 'Username', password: 'Password', confirmPwd: 'Confirm Password', + code: 'Verification Code', tab: { login: 'SIGN IN', register: 'SIGN UP', @@ -239,6 +241,7 @@ button: { login: 'SIGN IN', register: 'SIGN UP', + code: 'Send Code', }, }, settings: { diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js index 4b5ae98..905a832 100644 --- a/rsf-admin/src/i18n/zh.js +++ b/rsf-admin/src/i18n/zh.js @@ -229,9 +229,11 @@ title: '娆㈣繋浣跨敤', footer: 'Footer Goes Here', tenant: '鍏徃', - username: '璐﹀彿', + email: '閭鍦板潃', + username: '鐧诲綍璐﹀彿', password: '瀵嗙爜', confirmPwd: '纭瀵嗙爜', + code: '楠岃瘉鐮�', tab: { login: '鐧诲綍', register: '娉ㄥ唽', @@ -239,6 +241,7 @@ button: { login: '鐧诲綍', register: '娉ㄥ唽', + code: '鑾峰彇楠岃瘉鐮�', }, }, settings: { diff --git a/rsf-admin/src/page/login/Register.jsx b/rsf-admin/src/page/login/Register.jsx index 3e19a4f..881f5be 100644 --- a/rsf-admin/src/page/login/Register.jsx +++ b/rsf-admin/src/page/login/Register.jsx @@ -26,23 +26,54 @@ const notify = useNotify(); const login = useLogin(); const location = useLocation(); - const { systemInfo, tenantList } = props; + const { systemInfo } = props; const { control, watch, handleSubmit, setValue } = useForm(); + + const email = watch('email'); + const username = watch('username'); + const password = watch('password'); + const confirmPassword = watch('confirmPassword'); const [loading, setLoading] = useState(false); const [showPassword, setShowPassword] = useState(true); - const username = watch('username'); - const password = watch('password'); - const confirmPassword = watch('confirmPassword'); - const tenantId = watch('tenantId'); - useEffect(() => { - if (tenantList.length > 0 && !tenantId) { - setValue('tenantId', tenantList[0].id); + const [isCounting, setIsCounting] = useState(false); + const [countdown, setCountdown] = useState(60); + + // 澶勭悊楠岃瘉鐮佹寜閽偣鍑� + const handleSendCode = async () => { + // 杩欓噷鍋囪鍙戦�侀獙璇佺爜鐨勮姹� + const response = await fetch('/api/send-code'); + if (response.ok) { + setIsCounting(true); + localStorage.setItem('codeCountdown', 60); // 瀛樺偍鍊掕鏃跺埌鏈湴 } - }, [tenantList, setValue]); + }; + + // 鍊掕鏃跺姛鑳� + useEffect(() => { + const savedCountdown = localStorage.getItem('codeCountdown'); + if (savedCountdown && !isCounting) { + setCountdown(Number(savedCountdown)); + setIsCounting(true); + } + + const interval = setInterval(() => { + if (isCounting && countdown > 0) { + setCountdown(prev => prev - 1); + localStorage.setItem('codeCountdown', countdown - 1); + } else if (countdown <= 0) { + clearInterval(interval); + setIsCounting(false); + localStorage.removeItem('codeCountdown'); // 閲嶇疆 + } + }, 1000); + + return () => clearInterval(interval); + }, [countdown, isCounting]); + const onSubmit = (data) => { notify("Registration is not open yet"); @@ -85,34 +116,6 @@ > <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="" @@ -120,7 +123,7 @@ render={({ field }) => ( <TextField {...field} - label={translate('ra.auth.username')} + label={translate("page.login.username")} variant="standard" disabled={loading} autoFocus @@ -133,15 +136,23 @@ name="password" control={control} defaultValue="" - rules={{ required: true }} - render={({ field }) => ( + rules={{ + required: 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('ra.auth.password')} + 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"> @@ -164,8 +175,12 @@ name="confirmPassword" control={control} defaultValue="" - rules={{ required: true }} - render={({ field }) => ( + rules={{ + required: translate('ra.validation.required'), + validate: value => + value === password || translate('page.settings.resetPwd.tip.pwdNotMatch'), + }} + render={({ field, fieldState: { error } }) => ( <TextField {...field} label={translate('page.login.confirmPwd')} @@ -173,6 +188,8 @@ variant="standard" disabled={loading} autoComplete="off" + error={!!error} + helperText={error?.message || ""} InputProps={{ endAdornment: ( <InputAdornment position="end"> @@ -191,12 +208,80 @@ )} /> + <Controller + name="email" + control={control} + defaultValue="" + rules={{ + required: translate('ra.validation.required'), + pattern: { + value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, + message: translate("ra.validation.email"), + }, + }} + render={({ field, fieldState: { error } }) => ( + <TextField + {...field} + label={translate('page.login.email')} + variant="standard" + disabled={loading} + // autoComplete="off" + error={!!error} + helperText={error ? error.message : ""} + /> + )} + /> + + <Box display="flex" alignItems="center" justifyContent='center' width="100%"> + <Controller + name="code" + control={control} + defaultValue="" + rules={{ + required: translate('ra.validation.required'), + }} + render={({ field, fieldState: { error } }) => ( + <TextField + {...field} + label={translate('page.login.code')} + variant="standard" + disabled={loading} + autoComplete="off" + error={!!error} + helperText={error ? error.message : ""} + sx={{ + width: '65%', + mr: 2, + }} + /> + )} + /> + + <Button + variant="outlined" + onClick={handleSendCode} + disabled={isCounting || loading} + sx={{ + mt: 1, + }} + > + {isCounting ? ( + <> + <CircularProgress size={20} color="primary" sx={{ marginRight: 1 }} /> + {`${countdown}s`} + </> + ) : ( + translate('page.login.button.code') + )} + </Button> + </Box> + <Box /> <Button type="submit" variant="contained" - disabled={loading || !(tenantId && username && password && confirmPassword)} + disabled={loading || !(email && username && password && confirmPassword)} sx={{ backgroundColor: "#3D4BA7" }} -- Gitblit v1.9.1