mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-25 19:52:48 +00:00
parent
51c246ef02
commit
22b519f5ba
|
|
@ -75,6 +75,7 @@
|
|||
"react-dplayer": "^0.4.1",
|
||||
"react-hotkeys": "^2.0.0",
|
||||
"react-lazy-load-image-component": "^1.3.2",
|
||||
"react-load-script": "^0.0.6",
|
||||
"react-monaco-editor": "^0.36.0",
|
||||
"react-pdf": "^4.1.0",
|
||||
"react-photo-view": "^0.4.0",
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import Share from "./component/Admin/Share/Share";
|
|||
import Download from "./component/Admin/Task/Download";
|
||||
import Task from "./component/Admin/Task/Task";
|
||||
import Import from "./component/Admin/File/Import";
|
||||
import Captcha from "./component/Admin/Setting/Captcha";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
|
|
@ -114,6 +115,10 @@ export default function Admin() {
|
|||
<ImageSetting />
|
||||
</Route>
|
||||
|
||||
<Route path={`${path}/captcha`}>
|
||||
<Captcha />
|
||||
</Route>
|
||||
|
||||
<Route path={`${path}/policy`} exact>
|
||||
<Policy />
|
||||
</Route>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import List from "@material-ui/core/List";
|
|||
import ListItem from "@material-ui/core/ListItem";
|
||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import ListItemText from "@material-ui/core/ListItemText";
|
||||
import Code from "@material-ui/icons/Code";
|
||||
import { lighten, makeStyles, useTheme } from "@material-ui/core/styles";
|
||||
import Toolbar from "@material-ui/core/Toolbar";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
|
|
@ -219,6 +220,11 @@ const items = [
|
|||
path: "image",
|
||||
icon: <Image />,
|
||||
},
|
||||
{
|
||||
title: "验证码",
|
||||
path: "captcha",
|
||||
icon: <Code />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import Button from "@material-ui/core/Button";
|
|||
import FormControl from "@material-ui/core/FormControl";
|
||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
||||
import FormHelperText from "@material-ui/core/FormHelperText";
|
||||
import Input from "@material-ui/core/Input";
|
||||
import InputLabel from "@material-ui/core/InputLabel";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import Select from "@material-ui/core/Select";
|
||||
|
|
@ -14,7 +13,6 @@ import { useDispatch } from "react-redux";
|
|||
import { toggleSnackbar } from "../../../actions";
|
||||
import API from "../../../middleware/Api";
|
||||
import AlertDialog from "../Dialogs/Alert";
|
||||
import Link from "@material-ui/core/Link";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
|
|
@ -46,9 +44,6 @@ export default function Access() {
|
|||
reg_captcha: "0",
|
||||
forget_captcha: "0",
|
||||
authn_enabled: "0",
|
||||
captcha_IsUseReCaptcha: "0",
|
||||
captcha_ReCaptchaKey: "defaultKey",
|
||||
captcha_ReCaptchaSecret: "defaultSecret",
|
||||
});
|
||||
const [siteURL, setSiteURL] = useState("");
|
||||
const [groups, setGroups] = useState([]);
|
||||
|
|
@ -248,86 +243,6 @@ export default function Access() {
|
|||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={
|
||||
options.captcha_IsUseReCaptcha ===
|
||||
"1"
|
||||
}
|
||||
onChange={handleChange(
|
||||
"captcha_IsUseReCaptcha"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
label="使用 reCaptcha V2 验证码"
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
是否使用 reCaptcha V2 验证码
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
{options.captcha_IsUseReCaptcha === "1" && (
|
||||
<>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
Site KEY
|
||||
</InputLabel>
|
||||
<Input
|
||||
required
|
||||
value={options.captcha_ReCaptchaKey}
|
||||
onChange={handleInputChange(
|
||||
"captcha_ReCaptchaKey"
|
||||
)}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
<Link
|
||||
href={
|
||||
"https://www.google.com/recaptcha/admin/create"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
应用管理页面
|
||||
</Link>{" "}
|
||||
获取到的的 网站密钥
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
Secret
|
||||
</InputLabel>
|
||||
<Input
|
||||
required
|
||||
value={
|
||||
options.captcha_ReCaptchaSecret
|
||||
}
|
||||
onChange={handleInputChange(
|
||||
"captcha_ReCaptchaSecret"
|
||||
)}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
<Link
|
||||
href={
|
||||
"https://www.google.com/recaptcha/admin/create"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
应用管理页面
|
||||
</Link>{" "}
|
||||
获取到的的 秘钥
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<FormControlLabel
|
||||
|
|
|
|||
|
|
@ -0,0 +1,406 @@
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import InputLabel from "@material-ui/core/InputLabel";
|
||||
import FormControl from "@material-ui/core/FormControl";
|
||||
import FormHelperText from "@material-ui/core/FormHelperText";
|
||||
import Button from "@material-ui/core/Button";
|
||||
import API from "../../../middleware/Api";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { toggleSnackbar } from "../../../actions";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import Input from "@material-ui/core/Input";
|
||||
import Link from "@material-ui/core/Link";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
[theme.breakpoints.up("md")]: {
|
||||
marginLeft: 100,
|
||||
},
|
||||
marginBottom: 40,
|
||||
},
|
||||
form: {
|
||||
maxWidth: 400,
|
||||
marginTop: 20,
|
||||
marginBottom: 20,
|
||||
},
|
||||
formContainer: {
|
||||
[theme.breakpoints.up("md")]: {
|
||||
padding: "0px 24px 0 24px",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export default function Captcha() {
|
||||
const classes = useStyles();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [options, setOptions] = useState({
|
||||
captcha_type: "normal",
|
||||
captcha_height: "1",
|
||||
captcha_width: "1",
|
||||
captcha_mode: "3",
|
||||
captcha_CaptchaLen: "",
|
||||
captcha_ReCaptchaKey: "",
|
||||
captcha_ReCaptchaSecret: "",
|
||||
captcha_TCaptcha_CaptchaAppId: "",
|
||||
captcha_TCaptcha_AppSecretKey: "",
|
||||
captcha_TCaptcha_SecretId: "",
|
||||
captcha_TCaptcha_SecretKey: "",
|
||||
});
|
||||
|
||||
const handleChange = (name) => (event) => {
|
||||
setOptions({
|
||||
...options,
|
||||
[name]: event.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
(vertical, horizontal, msg, color) =>
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
API.post("/admin/setting", {
|
||||
keys: Object.keys(options),
|
||||
})
|
||||
.then((response) => {
|
||||
setOptions(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
});
|
||||
// eslint-disable-next-line
|
||||
}, []);
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
const option = [];
|
||||
Object.keys(options).forEach((k) => {
|
||||
option.push({
|
||||
key: k,
|
||||
value: options[k],
|
||||
});
|
||||
});
|
||||
API.patch("/admin/setting", {
|
||||
options: option,
|
||||
})
|
||||
.then(() => {
|
||||
ToggleSnackbar("top", "right", "设置已更改", "success");
|
||||
})
|
||||
.catch((error) => {
|
||||
ToggleSnackbar("top", "right", error.message, "error");
|
||||
})
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={submit}>
|
||||
<div className={classes.root}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
验证码
|
||||
</Typography>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
验证码类型
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={options.captcha_type}
|
||||
onChange={handleChange("captcha_type")}
|
||||
required
|
||||
>
|
||||
<MenuItem value={"normal"}>普通</MenuItem>
|
||||
<MenuItem value={"recaptcha"}>
|
||||
reCAPTCHA V2
|
||||
</MenuItem>
|
||||
<MenuItem value={"tcaptcha"}>
|
||||
腾讯云验证码
|
||||
</MenuItem>
|
||||
</Select>
|
||||
<FormHelperText id="component-helper-text">
|
||||
验证码类型
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{options.captcha_type === "normal" && (
|
||||
<div className={classes.root}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
普通验证码
|
||||
</Typography>
|
||||
<div className={classes.formContainer}>
|
||||
<div className={classes.form}>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
宽度
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min: 1,
|
||||
step: 1,
|
||||
}}
|
||||
value={options.captcha_width}
|
||||
onChange={handleChange("captcha_width")}
|
||||
required
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
高度
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min: 1,
|
||||
step: 1,
|
||||
}}
|
||||
value={options.captcha_height}
|
||||
onChange={handleChange(
|
||||
"captcha_height"
|
||||
)}
|
||||
required
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
模式
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={options.captcha_mode}
|
||||
onChange={handleChange("captcha_mode")}
|
||||
required
|
||||
>
|
||||
<MenuItem value={"0"}>数字</MenuItem>
|
||||
<MenuItem value={"1"}>字母</MenuItem>
|
||||
<MenuItem value={"2"}>算数</MenuItem>
|
||||
<MenuItem value={"3"}>
|
||||
数字+字母
|
||||
</MenuItem>
|
||||
</Select>
|
||||
<FormHelperText id="component-helper-text">
|
||||
验证码的形式
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{options.captcha_type === "recaptcha" && (
|
||||
<div className={classes.root}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
reCAPTCHA V2
|
||||
</Typography>
|
||||
<div className={classes.formContainer}>
|
||||
<div className={classes.form}>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
Site KEY
|
||||
</InputLabel>
|
||||
<Input
|
||||
required
|
||||
value={options.captcha_ReCaptchaKey}
|
||||
onChange={handleChange(
|
||||
"captcha_ReCaptchaKey"
|
||||
)}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
<Link
|
||||
href={
|
||||
"https://www.google.com/recaptcha/admin/create"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
应用管理页面
|
||||
</Link>{" "}
|
||||
获取到的的 网站密钥
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
Secret
|
||||
</InputLabel>
|
||||
<Input
|
||||
required
|
||||
value={
|
||||
options.captcha_ReCaptchaSecret
|
||||
}
|
||||
onChange={handleChange(
|
||||
"captcha_ReCaptchaSecret"
|
||||
)}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
<Link
|
||||
href={
|
||||
"https://www.google.com/recaptcha/admin/create"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
应用管理页面
|
||||
</Link>{" "}
|
||||
获取到的的 秘钥
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{options.captcha_type === "tcaptcha" && (
|
||||
<div className={classes.root}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
腾讯云验证码
|
||||
</Typography>
|
||||
<div className={classes.formContainer}>
|
||||
<div className={classes.form}>
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
SecretId
|
||||
</InputLabel>
|
||||
<Input
|
||||
required
|
||||
value={
|
||||
options.captcha_TCaptcha_SecretId
|
||||
}
|
||||
onChange={handleChange(
|
||||
"captcha_TCaptcha_SecretId"
|
||||
)}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
<Link
|
||||
href={
|
||||
"https://console.cloud.tencent.com/capi"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
访问密钥页面
|
||||
</Link>{" "}
|
||||
获取到的的 SecretId
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
SecretKey
|
||||
</InputLabel>
|
||||
<Input
|
||||
required
|
||||
value={
|
||||
options.captcha_TCaptcha_SecretKey
|
||||
}
|
||||
onChange={handleChange(
|
||||
"captcha_TCaptcha_SecretKey"
|
||||
)}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
<Link
|
||||
href={
|
||||
"https://console.cloud.tencent.com/capi"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
访问密钥页面
|
||||
</Link>{" "}
|
||||
获取到的的 SecretKey
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
APPID
|
||||
</InputLabel>
|
||||
<Input
|
||||
required
|
||||
value={
|
||||
options.captcha_TCaptcha_CaptchaAppId
|
||||
}
|
||||
onChange={handleChange(
|
||||
"captcha_TCaptcha_CaptchaAppId"
|
||||
)}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
<Link
|
||||
href={
|
||||
"https://console.cloud.tencent.com/captcha/graphical"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
图形验证页面
|
||||
</Link>{" "}
|
||||
获取到的的 APPID
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
App Secret Key
|
||||
</InputLabel>
|
||||
<Input
|
||||
required
|
||||
value={
|
||||
options.captcha_TCaptcha_AppSecretKey
|
||||
}
|
||||
onChange={handleChange(
|
||||
"captcha_TCaptcha_AppSecretKey"
|
||||
)}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text">
|
||||
<Link
|
||||
href={
|
||||
"https://console.cloud.tencent.com/captcha/graphical"
|
||||
}
|
||||
target={"_blank"}
|
||||
>
|
||||
图形验证页面
|
||||
</Link>{" "}
|
||||
获取到的的 App Secret Key
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={classes.root}>
|
||||
<Button
|
||||
disabled={loading}
|
||||
type={"submit"}
|
||||
variant={"contained"}
|
||||
color={"primary"}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -3,8 +3,6 @@ import FormControl from "@material-ui/core/FormControl";
|
|||
import FormHelperText from "@material-ui/core/FormHelperText";
|
||||
import Input from "@material-ui/core/Input";
|
||||
import InputLabel from "@material-ui/core/InputLabel";
|
||||
import MenuItem from "@material-ui/core/MenuItem";
|
||||
import Select from "@material-ui/core/Select";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
|
|
@ -44,10 +42,6 @@ export default function ImageSetting() {
|
|||
avatar_size_s: "",
|
||||
thumb_width: "",
|
||||
thumb_height: "",
|
||||
captcha_height: "1",
|
||||
captcha_width: "1",
|
||||
captcha_mode: "3",
|
||||
captcha_CaptchaLen: "",
|
||||
});
|
||||
|
||||
const handleChange = (name) => (event) => {
|
||||
|
|
@ -260,70 +254,6 @@ export default function ImageSetting() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className={classes.root}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
验证码
|
||||
</Typography>
|
||||
<div className={classes.formContainer}>
|
||||
<div className={classes.form}>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
宽度
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min: 1,
|
||||
step: 1,
|
||||
}}
|
||||
value={options.captcha_width}
|
||||
onChange={handleChange("captcha_width")}
|
||||
required
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
高度
|
||||
</InputLabel>
|
||||
<Input
|
||||
type={"number"}
|
||||
inputProps={{
|
||||
min: 1,
|
||||
step: 1,
|
||||
}}
|
||||
value={options.captcha_height}
|
||||
onChange={handleChange("captcha_height")}
|
||||
required
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
|
||||
<div className={classes.form}>
|
||||
<FormControl>
|
||||
<InputLabel htmlFor="component-helper">
|
||||
模式
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={options.captcha_mode}
|
||||
onChange={handleChange("captcha_mode")}
|
||||
required
|
||||
>
|
||||
<MenuItem value={"0"}>数字</MenuItem>
|
||||
<MenuItem value={"1"}>字母</MenuItem>
|
||||
<MenuItem value={"2"}>算数</MenuItem>
|
||||
<MenuItem value={"3"}>数字+字母</MenuItem>
|
||||
</Select>
|
||||
<FormHelperText id="component-helper-text">
|
||||
验证码的形式
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={classes.root}>
|
||||
<Button
|
||||
disabled={loading}
|
||||
|
|
|
|||
|
|
@ -1,34 +1,34 @@
|
|||
import React, { useCallback, useState, useEffect } from "react";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import LockOutlinedIcon from "@material-ui/icons/LockOutlined";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import {
|
||||
toggleSnackbar,
|
||||
Avatar,
|
||||
Button,
|
||||
Divider,
|
||||
FormControl,
|
||||
Input,
|
||||
InputLabel,
|
||||
Link,
|
||||
makeStyles,
|
||||
Paper,
|
||||
Typography,
|
||||
} from "@material-ui/core";
|
||||
import {
|
||||
applyThemes,
|
||||
setSessionStatus,
|
||||
toggleSnackbar,
|
||||
} from "../../actions/index";
|
||||
import Placeholder from "../Placeholder/Captcha";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import API from "../../middleware/Api";
|
||||
import Auth from "../../middleware/Auth";
|
||||
import {
|
||||
Button,
|
||||
FormControl,
|
||||
Divider,
|
||||
Link,
|
||||
Input,
|
||||
InputLabel,
|
||||
Paper,
|
||||
Avatar,
|
||||
Typography,
|
||||
} from "@material-ui/core";
|
||||
import { bufferDecode, bufferEncode } from "../../utils/index";
|
||||
import { enableUploaderLoad } from "../../middleware/Init";
|
||||
import { Fingerprint, VpnKey } from "@material-ui/icons";
|
||||
import VpnIcon from "@material-ui/icons/VpnKeyOutlined";
|
||||
import { useLocation } from "react-router";
|
||||
import ReCaptcha from "./ReCaptcha";
|
||||
import { ICPFooter } from "../Common/ICPFooter";
|
||||
import { useCaptcha } from "../../hooks/useCaptcha";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
layout: {
|
||||
width: "auto",
|
||||
|
|
@ -94,22 +94,14 @@ function useQuery() {
|
|||
function LoginForm() {
|
||||
const [email, setEmail] = useState("");
|
||||
const [pwd, setPwd] = useState("");
|
||||
const [captcha, setCaptcha] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [useAuthn, setUseAuthn] = useState(false);
|
||||
const [captchaData, setCaptchaData] = useState(null);
|
||||
const [twoFA, setTwoFA] = useState(false);
|
||||
const [faCode, setFACode] = useState("");
|
||||
|
||||
const loginCaptcha = useSelector((state) => state.siteConfig.loginCaptcha);
|
||||
const title = useSelector((state) => state.siteConfig.title);
|
||||
const authn = useSelector((state) => state.siteConfig.authn);
|
||||
const useReCaptcha = useSelector(
|
||||
(state) => state.siteConfig.captcha_IsUseReCaptcha
|
||||
);
|
||||
const reCaptchaKey = useSelector(
|
||||
(state) => state.siteConfig.captcha_ReCaptchaKey
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
|
|
@ -127,31 +119,21 @@ function LoginForm() {
|
|||
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const {
|
||||
captchaLoading,
|
||||
isValidate,
|
||||
validate,
|
||||
CaptchaRender,
|
||||
captchaRefreshRef,
|
||||
captchaParamsRef,
|
||||
} = useCaptcha();
|
||||
const query = useQuery();
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
const refreshCaptcha = useCallback(() => {
|
||||
API.get("/site/captcha")
|
||||
.then((response) => {
|
||||
setCaptchaData(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"无法加载验证码:" + error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setEmail(query.get("username"));
|
||||
if (loginCaptcha && !useReCaptcha) {
|
||||
refreshCaptcha();
|
||||
}
|
||||
}, [location, loginCaptcha]);
|
||||
}, [location]);
|
||||
|
||||
const afterLogin = (data) => {
|
||||
Auth.authenticate(data);
|
||||
|
|
@ -235,10 +217,14 @@ function LoginForm() {
|
|||
const login = (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
if (!isValidate.current.isValidate && loginCaptcha) {
|
||||
validate(() => login(e), setLoading);
|
||||
return;
|
||||
}
|
||||
API.post("/user/session", {
|
||||
userName: email,
|
||||
Password: pwd,
|
||||
captchaCode: captcha,
|
||||
...captchaParamsRef.current,
|
||||
})
|
||||
.then((response) => {
|
||||
setLoading(false);
|
||||
|
|
@ -251,9 +237,7 @@ function LoginForm() {
|
|||
.catch((error) => {
|
||||
setLoading(false);
|
||||
ToggleSnackbar("top", "right", error.message, "warning");
|
||||
if (!useReCaptcha) {
|
||||
refreshCaptcha();
|
||||
}
|
||||
captchaRefreshRef.current();
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -315,78 +299,17 @@ function LoginForm() {
|
|||
autoComplete
|
||||
/>
|
||||
</FormControl>
|
||||
{loginCaptcha && !useReCaptcha && (
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
>
|
||||
<InputLabel htmlFor="captcha">
|
||||
验证码
|
||||
</InputLabel>
|
||||
<Input
|
||||
name="captcha"
|
||||
onChange={(e) =>
|
||||
setCaptcha(e.target.value)
|
||||
}
|
||||
type="text"
|
||||
id="captcha"
|
||||
value={captcha}
|
||||
autoComplete
|
||||
/>
|
||||
</FormControl>{" "}
|
||||
<div>
|
||||
{captchaData === null && (
|
||||
<div
|
||||
className={
|
||||
classes.captchaPlaceholder
|
||||
}
|
||||
>
|
||||
<Placeholder />
|
||||
</div>
|
||||
)}
|
||||
{captchaData !== null && (
|
||||
<img
|
||||
src={captchaData}
|
||||
alt="captcha"
|
||||
onClick={refreshCaptcha}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loginCaptcha && useReCaptcha && (
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
>
|
||||
<div>
|
||||
<ReCaptcha
|
||||
style={{
|
||||
display: "inline-block",
|
||||
}}
|
||||
sitekey={reCaptchaKey}
|
||||
onChange={(value) =>
|
||||
setCaptcha(value)
|
||||
}
|
||||
id="captcha"
|
||||
name="captcha"
|
||||
/>
|
||||
</div>
|
||||
</FormControl>{" "}
|
||||
</div>
|
||||
)}
|
||||
{loginCaptcha && <CaptchaRender />}
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={loading}
|
||||
disabled={
|
||||
loading ||
|
||||
(loginCaptcha ? captchaLoading : false)
|
||||
}
|
||||
className={classes.submit}
|
||||
>
|
||||
登录
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
import React, { useCallback, useState, useEffect } from "react";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import RegIcon from "@material-ui/icons/AssignmentIndOutlined";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import { toggleSnackbar } from "../../actions/index";
|
||||
import Placeholder from "../Placeholder/Captcha";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import API from "../../middleware/Api";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
FormControl,
|
||||
Divider,
|
||||
Link,
|
||||
FormControl,
|
||||
Input,
|
||||
InputLabel,
|
||||
Link,
|
||||
makeStyles,
|
||||
Paper,
|
||||
Avatar,
|
||||
Typography,
|
||||
} from "@material-ui/core";
|
||||
import { toggleSnackbar } from "../../actions/index";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import API from "../../middleware/Api";
|
||||
import EmailIcon from "@material-ui/icons/EmailOutlined";
|
||||
import ReCaptcha from "./ReCaptcha";
|
||||
import { useCaptcha } from "../../hooks/useCaptcha";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
layout: {
|
||||
width: "auto",
|
||||
|
|
@ -86,20 +86,12 @@ function Register() {
|
|||
email: "",
|
||||
password: "",
|
||||
password_repeat: "",
|
||||
captcha: "",
|
||||
});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [emailActive, setEmailActive] = useState(false);
|
||||
const [captchaData, setCaptchaData] = useState(null);
|
||||
|
||||
const title = useSelector((state) => state.siteConfig.title);
|
||||
const regCaptcha = useSelector((state) => state.siteConfig.regCaptcha);
|
||||
const useReCaptcha = useSelector(
|
||||
(state) => state.siteConfig.captcha_IsUseReCaptcha
|
||||
);
|
||||
const reCaptchaKey = useSelector(
|
||||
(state) => state.siteConfig.captcha_ReCaptchaKey
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
|
|
@ -116,23 +108,16 @@ function Register() {
|
|||
});
|
||||
};
|
||||
|
||||
const {
|
||||
captchaLoading,
|
||||
isValidate,
|
||||
validate,
|
||||
CaptchaRender,
|
||||
captchaRefreshRef,
|
||||
captchaParamsRef,
|
||||
} = useCaptcha();
|
||||
const classes = useStyles();
|
||||
|
||||
const refreshCaptcha = useCallback(() => {
|
||||
API.get("/site/captcha")
|
||||
.then((response) => {
|
||||
setCaptchaData(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"无法加载验证码:" + error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const register = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
|
|
@ -142,10 +127,14 @@ function Register() {
|
|||
}
|
||||
|
||||
setLoading(true);
|
||||
if (!isValidate.current.isValidate && regCaptcha) {
|
||||
validate(() => register(e), setLoading);
|
||||
return;
|
||||
}
|
||||
API.post("/user", {
|
||||
userName: input.email,
|
||||
Password: input.password,
|
||||
captchaCode: input.captcha,
|
||||
...captchaParamsRef.current,
|
||||
})
|
||||
.then((response) => {
|
||||
setLoading(false);
|
||||
|
|
@ -159,18 +148,10 @@ function Register() {
|
|||
.catch((error) => {
|
||||
setLoading(false);
|
||||
ToggleSnackbar("top", "right", error.message, "warning");
|
||||
if (!useReCaptcha) {
|
||||
refreshCaptcha();
|
||||
}
|
||||
captchaRefreshRef.current();
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (regCaptcha && !useReCaptcha) {
|
||||
refreshCaptcha();
|
||||
}
|
||||
}, [regCaptcha]);
|
||||
|
||||
return (
|
||||
<div className={classes.layout}>
|
||||
<>
|
||||
|
|
@ -224,77 +205,17 @@ function Register() {
|
|||
autoComplete
|
||||
/>
|
||||
</FormControl>
|
||||
{regCaptcha && !useReCaptcha && (
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
>
|
||||
<InputLabel htmlFor="captcha">
|
||||
验证码
|
||||
</InputLabel>
|
||||
<Input
|
||||
name="captcha"
|
||||
onChange={handleInputChange(
|
||||
"captcha"
|
||||
)}
|
||||
type="text"
|
||||
id="captcha"
|
||||
value={input.captcha}
|
||||
autoComplete
|
||||
/>
|
||||
</FormControl>{" "}
|
||||
<div>
|
||||
{captchaData === null && (
|
||||
<div
|
||||
className={
|
||||
classes.captchaPlaceholder
|
||||
}
|
||||
>
|
||||
<Placeholder />
|
||||
</div>
|
||||
)}
|
||||
{captchaData !== null && (
|
||||
<img
|
||||
src={captchaData}
|
||||
alt="captcha"
|
||||
onClick={refreshCaptcha}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{regCaptcha && useReCaptcha && (
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
>
|
||||
<ReCaptcha
|
||||
style={{ display: "inline-block" }}
|
||||
sitekey={reCaptchaKey}
|
||||
onChange={(value) =>
|
||||
setInput({
|
||||
...input,
|
||||
captcha: value,
|
||||
})
|
||||
}
|
||||
id="captcha"
|
||||
name="captcha"
|
||||
/>
|
||||
</FormControl>{" "}
|
||||
</div>
|
||||
)}
|
||||
{regCaptcha && <CaptchaRender />}
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={loading}
|
||||
disabled={
|
||||
loading ||
|
||||
(regCaptcha ? captchaLoading : false)
|
||||
}
|
||||
className={classes.submit}
|
||||
>
|
||||
注册账号
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
import React, { useCallback, useState, useEffect } from "react";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import { toggleSnackbar } from "../../actions/index";
|
||||
import Placeholder from "../Placeholder/Captcha";
|
||||
import API from "../../middleware/Api";
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
FormControl,
|
||||
Divider,
|
||||
Link,
|
||||
FormControl,
|
||||
Input,
|
||||
InputLabel,
|
||||
Link,
|
||||
makeStyles,
|
||||
Paper,
|
||||
Avatar,
|
||||
Typography,
|
||||
} from "@material-ui/core";
|
||||
import { toggleSnackbar } from "../../actions/index";
|
||||
import API from "../../middleware/Api";
|
||||
import KeyIcon from "@material-ui/icons/VpnKeyOutlined";
|
||||
import ReCaptcha from "./ReCaptcha";
|
||||
import { useCaptcha } from "../../hooks/useCaptcha";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
layout: {
|
||||
width: "auto",
|
||||
|
|
@ -64,19 +64,11 @@ const useStyles = makeStyles((theme) => ({
|
|||
function Reset() {
|
||||
const [input, setInput] = useState({
|
||||
email: "",
|
||||
captcha: "",
|
||||
});
|
||||
const [captchaData, setCaptchaData] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const forgetCaptcha = useSelector(
|
||||
(state) => state.siteConfig.forgetCaptcha
|
||||
);
|
||||
const useReCaptcha = useSelector(
|
||||
(state) => state.siteConfig.captcha_IsUseReCaptcha
|
||||
);
|
||||
const reCaptchaKey = useSelector(
|
||||
(state) => state.siteConfig.captcha_ReCaptchaKey
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
(vertical, horizontal, msg, color) =>
|
||||
|
|
@ -90,34 +82,25 @@ function Reset() {
|
|||
});
|
||||
};
|
||||
|
||||
const refreshCaptcha = () => {
|
||||
API.get("/site/captcha")
|
||||
.then((response) => {
|
||||
setCaptchaData(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"无法加载验证码:" + error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (forgetCaptcha && !useReCaptcha) {
|
||||
refreshCaptcha();
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [forgetCaptcha]);
|
||||
const {
|
||||
captchaLoading,
|
||||
isValidate,
|
||||
validate,
|
||||
CaptchaRender,
|
||||
captchaRefreshRef,
|
||||
captchaParamsRef,
|
||||
} = useCaptcha();
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
if (!isValidate.current.isValidate && forgetCaptcha) {
|
||||
validate(() => submit(e), setLoading);
|
||||
return;
|
||||
}
|
||||
API.post("/user/reset", {
|
||||
userName: input.email,
|
||||
captchaCode: input.captcha,
|
||||
...captchaParamsRef.current,
|
||||
})
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
|
|
@ -131,9 +114,7 @@ function Reset() {
|
|||
.catch((error) => {
|
||||
setLoading(false);
|
||||
ToggleSnackbar("top", "right", error.message, "warning");
|
||||
if (!useReCaptcha) {
|
||||
refreshCaptcha();
|
||||
}
|
||||
captchaRefreshRef.current();
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -161,61 +142,15 @@ function Reset() {
|
|||
autoFocus
|
||||
/>
|
||||
</FormControl>
|
||||
{forgetCaptcha && !useReCaptcha && (
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="captcha">
|
||||
验证码
|
||||
</InputLabel>
|
||||
<Input
|
||||
name="captcha"
|
||||
onChange={handleInputChange("captcha")}
|
||||
type="text"
|
||||
id="captcha"
|
||||
value={input.captcha}
|
||||
autoComplete
|
||||
/>
|
||||
</FormControl>{" "}
|
||||
<div>
|
||||
{captchaData === null && (
|
||||
<div className={classes.captchaPlaceholder}>
|
||||
<Placeholder />
|
||||
</div>
|
||||
)}
|
||||
{captchaData !== null && (
|
||||
<img
|
||||
src={captchaData}
|
||||
alt="captcha"
|
||||
onClick={refreshCaptcha}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{forgetCaptcha && useReCaptcha && (
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<ReCaptcha
|
||||
style={{ display: "inline-block" }}
|
||||
sitekey={reCaptchaKey}
|
||||
onChange={(value) =>
|
||||
setInput({
|
||||
...input,
|
||||
captcha: value,
|
||||
})
|
||||
}
|
||||
id="captcha"
|
||||
name="captcha"
|
||||
/>
|
||||
</FormControl>{" "}
|
||||
</div>
|
||||
)}
|
||||
{forgetCaptcha && <CaptchaRender />}
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={loading}
|
||||
disabled={
|
||||
loading || (forgetCaptcha ? captchaLoading : false)
|
||||
}
|
||||
className={classes.submit}
|
||||
>
|
||||
发送密码重置邮件
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { toggleSnackbar } from "../actions";
|
||||
import API from "../middleware/Api";
|
||||
import { FormControl, Input, InputLabel } from "@material-ui/core";
|
||||
import Placeholder from "../component/Placeholder/Captcha";
|
||||
import { defaultValidate, useStyle } from "./useCaptcha";
|
||||
|
||||
const NormalCaptcha = forwardRef(function NormalCaptcha(
|
||||
{ captchaRef, setLoading },
|
||||
ref
|
||||
) {
|
||||
const classes = useStyle();
|
||||
|
||||
const [captcha, setCaptcha] = useState("");
|
||||
const [captchaData, setCaptchaData] = useState(null);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const ToggleSnackbar = useCallback(
|
||||
(vertical, horizontal, msg, color) =>
|
||||
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const refreshCaptcha = () => {
|
||||
API.get("/site/captcha")
|
||||
.then((response) => {
|
||||
setCaptchaData(response.data);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
ToggleSnackbar(
|
||||
"top",
|
||||
"right",
|
||||
"无法加载验证码:" + error.message,
|
||||
"error"
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
ref.current = refreshCaptcha;
|
||||
refreshCaptcha();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
captchaRef.current.captchaCode = captcha;
|
||||
}, [captcha]);
|
||||
|
||||
return (
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<InputLabel htmlFor="captcha">验证码</InputLabel>
|
||||
<Input
|
||||
name="captcha"
|
||||
onChange={(e) => setCaptcha(e.target.value)}
|
||||
type="text"
|
||||
id="captcha"
|
||||
value={captcha}
|
||||
autoComplete
|
||||
/>
|
||||
</FormControl>{" "}
|
||||
<div>
|
||||
{captchaData === null && (
|
||||
<div className={classes.captchaPlaceholder}>
|
||||
<Placeholder />
|
||||
</div>
|
||||
)}
|
||||
{captchaData !== null && (
|
||||
<img
|
||||
src={captchaData}
|
||||
alt="captcha"
|
||||
onClick={refreshCaptcha}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default function useNormalCaptcha(captchaRefreshRef, setLoading) {
|
||||
const isValidate = useRef({
|
||||
isValidate: true,
|
||||
});
|
||||
|
||||
const captchaParamsRef = useRef({
|
||||
captchaCode: "",
|
||||
});
|
||||
|
||||
const CaptchaRender = useCallback(
|
||||
function Normal() {
|
||||
return (
|
||||
<NormalCaptcha
|
||||
captchaRef={captchaParamsRef}
|
||||
ref={captchaRefreshRef}
|
||||
setLoading={setLoading}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[captchaParamsRef, captchaRefreshRef, setLoading]
|
||||
);
|
||||
|
||||
return {
|
||||
isValidate,
|
||||
validate: defaultValidate,
|
||||
captchaParamsRef,
|
||||
CaptchaRender,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { FormControl } from "@material-ui/core";
|
||||
import ReCaptcha from "../component/Login/ReCaptcha";
|
||||
import { defaultValidate, useStyle } from "./useCaptcha";
|
||||
|
||||
const Recaptcha = ({ captchaRef, setLoading }) => {
|
||||
const classes = useStyle();
|
||||
|
||||
const [captcha, setCaptcha] = useState("");
|
||||
|
||||
const reCaptchaKey = useSelector(
|
||||
(state) => state.siteConfig.captcha_ReCaptchaKey
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
captchaRef.current.captchaCode = captcha;
|
||||
}, [captcha]);
|
||||
|
||||
useEffect(() => setLoading(false), []);
|
||||
|
||||
return (
|
||||
<div className={classes.captchaContainer}>
|
||||
<FormControl margin="normal" required fullWidth>
|
||||
<div>
|
||||
<ReCaptcha
|
||||
style={{
|
||||
display: "inline-block",
|
||||
}}
|
||||
sitekey={reCaptchaKey}
|
||||
onChange={(value) => setCaptcha(value)}
|
||||
id="captcha"
|
||||
name="captcha"
|
||||
/>
|
||||
</div>
|
||||
</FormControl>{" "}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default function useRecaptcha(setLoading) {
|
||||
const isValidate = useRef({
|
||||
isValidate: true,
|
||||
});
|
||||
|
||||
const captchaParamsRef = useRef({
|
||||
captchaCode: "",
|
||||
});
|
||||
|
||||
const CaptchaRender = useCallback(
|
||||
function RecaptchaRender() {
|
||||
return (
|
||||
<Recaptcha
|
||||
captchaRef={captchaParamsRef}
|
||||
setLoading={setLoading}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[captchaParamsRef, setLoading]
|
||||
);
|
||||
|
||||
return {
|
||||
isValidate,
|
||||
validate: defaultValidate,
|
||||
captchaParamsRef,
|
||||
CaptchaRender,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import React, { forwardRef, useCallback, useRef } from "react";
|
||||
import Script from "react-load-script";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
const TCaptcha = forwardRef(function TCaptcha(
|
||||
{ captchaRef, setLoading, isValidateRef, submitRef },
|
||||
ref
|
||||
) {
|
||||
const appid = useSelector(
|
||||
(state) => state.siteConfig.tcaptcha_captcha_app_id
|
||||
);
|
||||
const onLoad = () => {
|
||||
try {
|
||||
ref.current = new window.TencentCaptcha(appid, function (res) {
|
||||
if (res.ret === 0) {
|
||||
captchaRef.current.ticket = res.ticket;
|
||||
captchaRef.current.randstr = res.randstr;
|
||||
|
||||
isValidateRef.current.isValidate = true;
|
||||
submitRef.current.submit();
|
||||
console.log(submitRef);
|
||||
} else {
|
||||
submitRef.current.setLoading(false);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
return (
|
||||
<Script
|
||||
url={"https://ssl.captcha.qq.com/TCaptcha.js"}
|
||||
onLoad={onLoad}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default function useTCaptcha(setLoading) {
|
||||
const isValidate = useRef({
|
||||
isValidate: false,
|
||||
});
|
||||
const captchaParamsRef = useRef({
|
||||
ticket: "",
|
||||
randstr: "",
|
||||
});
|
||||
const submitRef = useRef({
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
submit: () => {},
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
setLoading: () => {},
|
||||
});
|
||||
|
||||
const captchaRef = useRef();
|
||||
|
||||
const CaptchaRender = useCallback(
|
||||
function TCaptchaRender() {
|
||||
return (
|
||||
<TCaptcha
|
||||
captchaRef={captchaParamsRef}
|
||||
setLoading={setLoading}
|
||||
isValidateRef={isValidate}
|
||||
submitRef={submitRef}
|
||||
ref={captchaRef}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[captchaParamsRef, setLoading, isValidate, submitRef, captchaRef]
|
||||
);
|
||||
|
||||
return {
|
||||
isValidate: isValidate,
|
||||
validate: (submit, setLoading) => {
|
||||
submitRef.current.submit = submit;
|
||||
submitRef.current.setLoading = setLoading;
|
||||
captchaRef.current.show();
|
||||
},
|
||||
captchaParamsRef,
|
||||
CaptchaRender,
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import { useSelector } from "react-redux";
|
||||
import { useRef, useState } from "react";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import useNormalCaptcha from "./normal";
|
||||
import useRecaptcha from "./recaptcha";
|
||||
import useTCaptcha from "./tcaptcha";
|
||||
|
||||
export const useStyle = makeStyles((theme) => ({
|
||||
captchaContainer: {
|
||||
display: "flex",
|
||||
marginTop: "10px",
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
display: "block",
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
||||
export const defaultValidate = (submit, setLoading) => {};
|
||||
|
||||
export const useCaptcha = () => {
|
||||
const captchaType = useSelector((state) => state.siteConfig.captcha_type);
|
||||
|
||||
const [captchaLoading, setCaptchaLoading] = useState(true);
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const captchaRefreshRef = useRef(() => {});
|
||||
|
||||
const normal = useNormalCaptcha(captchaRefreshRef, setCaptchaLoading);
|
||||
const recaptcha = useRecaptcha(setCaptchaLoading);
|
||||
const tcaptcha = useTCaptcha(setCaptchaLoading);
|
||||
|
||||
switch (captchaType) {
|
||||
case "normal":
|
||||
return { ...normal, captchaRefreshRef, captchaLoading };
|
||||
case "recaptcha":
|
||||
return { ...recaptcha, captchaRefreshRef, captchaLoading };
|
||||
case "tcaptcha":
|
||||
return { ...tcaptcha, captchaRefreshRef, captchaLoading };
|
||||
default:
|
||||
return { ...normal, captchaRefreshRef, captchaLoading };
|
||||
}
|
||||
};
|
||||
|
|
@ -61,8 +61,9 @@ export const initState = {
|
|||
},
|
||||
},
|
||||
},
|
||||
captcha_IsUseReCaptcha: false,
|
||||
captcha_ReCaptchaKey: "defaultKey",
|
||||
captcha_type: "normal",
|
||||
tcaptcha_captcha_app_id: "",
|
||||
},
|
||||
navigator: {
|
||||
path: "/",
|
||||
|
|
|
|||
Loading…
Reference in New Issue