Files
schisandra-cloud-storage-fr…/src/views/User/Login/index.tsx
2024-05-30 00:41:51 +08:00

419 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** @format */
import {
GithubOutlined,
GitlabOutlined,
LockOutlined,
MobileOutlined,
QqOutlined,
SafetyOutlined,
UserOutlined,
WechatOutlined,
} from "@ant-design/icons";
import {
CaptFieldRef,
ProFormCaptcha,
ProFormCheckbox,
ProFormText,
} from "@ant-design/pro-components";
import {
Alert,
Button,
ConfigProvider,
Divider,
Form,
Image,
message,
Space,
Tabs,
Tooltip,
} from "antd";
import { CSSProperties, useEffect, useRef, useState } from "react";
import logo from "@/assets/icons/schisandra.svg";
import qrCode from "@/assets/images/login_qrcode-landaiqing.jpg";
import styles from "./index.module.less";
import { observer } from "mobx-react";
import FooterComponent from "@/components/Footer";
import RotateCaptcha, { CaptchaInstance, type TicketInfoType } from "react-rotate-captcha";
import { get, load } from "@/api/captcha/index.ts";
import { getSms, oauthLogin } from "@/api/user";
import { VerfiyCaptcha } from "@/api/captcha/api.ts";
import { TinyColor } from "@ctrl/tinycolor";
// import useStore from '@/utils/store/useStore.tsx'
type LoginType = "account" | "phone";
const iconStyles: CSSProperties = {
color: "rgba(0, 0, 0, 0.2)",
fontSize: "18px",
verticalAlign: "middle",
cursor: "pointer",
};
export default observer(() => {
const [form] = Form.useForm();
const captcha = useRef<CaptchaInstance>(null);
const captchaRef = useRef<CaptFieldRef | null | undefined>();
const colors = ["#40e495", "#30dd8a", "#2bb673"];
const getHoverColors = (colors: string[]) =>
colors.map((color) => new TinyColor(color).lighten(5).toString());
const getActiveColors = (colors: string[]) =>
colors.map((color) => new TinyColor(color).darken(5).toString());
async function verify(token: string, deg: number): Promise<TicketInfoType> {
const data: any = {
token: token,
deg: deg,
};
const res = await VerfiyCaptcha(data);
return res;
}
const items = [
{
label: (
<span>
<UserOutlined />
</span>
),
key: "account",
},
{
label: (
<span>
<MobileOutlined />
</span>
),
key: "phone",
},
];
async function oAuthLogin(type: string) {
const res: any = await oauthLogin(type);
window.open(res.data, "_blank");
}
const [loginType, setLoginType] = useState<LoginType>("account");
async function openCaptcha() {
captcha.current!.open();
}
const onSubmit = async (formData: object) => {
openCaptcha().then(() => {
console.log(formData);
});
};
useEffect(() => {}, []);
return (
<RotateCaptcha get={get} load={load} verify={verify} limit={2} ref={captcha}>
<div className={styles.container}>
<div className={styles.content}>
<Space className={styles.content_content}>
<Space className={styles.login_content}>
<Space align="center" className={styles.mp_code}>
<Space direction="vertical" align="center">
<span className={styles.mp_code_title}></span>
<Image
preview={false}
height={210}
width={200}
className={styles.mp_code_img}
// src={generateMpRegCodeData.data?.qrCodeUrl}
src={qrCode}
/>
<Alert
// message={(<span>微信扫码<span>关注公众号</span></span>)}
description={
<div>
<span>
<span className={styles.mp_tips}>
</span>
</span>
<br />
</div>
}
// type="success"
showIcon={true}
className={styles.alert}
icon={<WechatOutlined />}
/>
</Space>
</Space>
<Form
form={form}
className={styles.login_form}
initialValues={{
autoLogin: true,
}}>
<Space direction="vertical" align="center">
<Space className={styles.logo}>
<img
alt="logo"
src={logo}
style={{ width: "44px", height: "44px" }}
/>
<span></span>
</Space>
<div className={styles.subTitle}></div>
</Space>
<Tabs
centered={true}
items={items}
activeKey={loginType}
onChange={(activeKey) =>
setLoginType(activeKey as LoginType)
}></Tabs>
{loginType === "account" && (
<>
<ProFormText
name="username"
fieldProps={{
size: "large",
prefix: <UserOutlined className={"prefixIcon"} />,
}}
placeholder={"请输入邮箱或电话号码"}
rules={[
{
required: true,
message: "请输入用户名!",
},
]}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: "large",
prefix: <LockOutlined className={"prefixIcon"} />,
}}
placeholder={"请输入密码"}
rules={[
{
required: true,
message: "请输入密码!",
},
{
pattern:
/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z\\W]{6,18}$/,
message:
"密码长度需在6~18位字符且必须包含字母和数字",
},
]}
/>
</>
)}
{loginType === "phone" && (
<>
<ProFormText
fieldProps={{
size: "large",
prefix: <MobileOutlined className={"prefixIcon"} />,
autoComplete: "off",
}}
name="mobile"
placeholder={"请输入手机号"}
rules={[
{
required: true,
message: "请输入手机号!",
},
{
pattern: /^1\d{10}$/,
message: "手机号格式错误!",
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: "large",
prefix: <SafetyOutlined className={"prefixIcon"} />,
}}
captchaProps={{
size: "large",
}}
placeholder={"请输入验证码"}
captchaTextRender={(timing: boolean) => {
if (timing) {
// return `${count} ${"获取验证码"}`;
return `${"获取验证码"}`;
}
return "获取验证码";
}}
name="captcha"
phoneName={"mobile"}
rules={[
{
required: true,
message: "请输入验证码!",
},
]}
fieldRef={captchaRef}
countDown={300}
onGetCaptcha={async (mobile: string) => {
const res: any = await getSms(mobile);
if (res && res.success) {
message.success(res.data, 3);
} else {
message.warning(res.data, 3);
}
}}
/>
</>
)}
<div style={{ marginBlockEnd: 14 }}>
<ProFormCheckbox noStyle name="autoLogin">
</ProFormCheckbox>
<a href={"/forget"} style={{ float: "right" }}>
</a>
</div>
<ConfigProvider
theme={{
components: {
Button: {
colorPrimary: `linear-gradient(116deg, ${colors.join(", ")})`,
colorPrimaryHover: `linear-gradient(116deg, ${getHoverColors(colors).join(", ")})`,
colorPrimaryActive: `linear-gradient(116deg, ${getActiveColors(colors).join(", ")})`,
lineWidth: 0,
},
},
}}>
<Button
type="primary"
block
size="large"
onClick={async () => {
let validateFields;
if (loginType === "account") {
validateFields = ["username", "password"];
} else {
validateFields = ["mobile", "captcha"];
}
await form
.validateFields(validateFields)
.then(async (values) => {
await onSubmit(values);
})
.catch((error) => {
console.error(error);
});
}}>
</Button>
</ConfigProvider>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
}}>
<Divider plain>
<span
style={{
color: "#CCC",
fontWeight: "normal",
fontSize: 14,
}}>
</span>
</Divider>
<Space align="center" size={24}>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
height: 40,
width: 40,
border: "1px solid #D4D8DD",
borderRadius: "50%",
}}>
<Tooltip title="QQ登录" color={"blue"}>
<QqOutlined
style={{ ...iconStyles, color: "#1677FF" }}
/>
</Tooltip>
</div>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
height: 40,
width: 40,
border: "1px solid #D4D8DD",
borderRadius: "50%",
}}>
<Tooltip title="企业微信登录" color={"green"}>
<WechatOutlined
style={{ ...iconStyles, color: "#08a327" }}
/>
</Tooltip>
</div>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
height: 40,
width: 40,
border: "1px solid #D4D8DD",
borderRadius: "50%",
}}>
<Tooltip title="github登录" color={"black"}>
<GithubOutlined
onClick={() => {
oAuthLogin("github").then();
}}
style={{ ...iconStyles, color: "#333333" }}
/>
</Tooltip>
</div>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
height: 40,
width: 40,
border: "1px solid #D4D8DD",
borderRadius: "50%",
}}>
<Tooltip title="gitee登录" color={"orange"}>
<GitlabOutlined
onClick={() => {
oAuthLogin("gitee").then();
}}
style={{ ...iconStyles, color: "#FF6A10" }}
/>
</Tooltip>
</div>
</Space>
</div>
</Form>
<a href="/register" className={styles.go_to_register}>
<span></span>
</a>
</Space>
</Space>
</div>
<FooterComponent></FooterComponent>
</div>
</RotateCaptcha>
);
});