feat: update

This commit is contained in:
landaiqing
2024-05-29 21:33:58 +08:00
parent cb9c827220
commit 4ce065214a
11 changed files with 173 additions and 144 deletions

View File

@@ -1,5 +1,7 @@
import type { TicketInfoType, TokenInfoType } from "react-rotate-captcha";
import { getCaptcha, VerfiyCaptcha } from "@/api/captcha/api.ts";
/** @format */
import type { TokenInfoType } from "react-rotate-captcha";
import { getCaptcha } from "@/api/captcha/api.ts";
export type ActionType = {
code: 0 | 1;
@@ -36,11 +38,10 @@ export function sleep(time: number) {
});
}
export async function verify(token: string, deg: number): Promise<TicketInfoType> {
const data: any = {
token: token,
deg: deg,
};
const res: any = await VerfiyCaptcha(data);
return res;
}
// export async function verify(token: string, deg: number): Promise<TicketInfoType> {
// const data: any = {
// token: token,
// deg: deg,
// };
// return await VerfiyCaptcha(data);
// }

View File

@@ -21,3 +21,26 @@ export const oauthLogin = (type: string) => {
method: "get",
});
};
/**
* 获取短信验证码
* @param phone
*/
export const getSms = (phone: string) => {
return web.request({
url: "/sms/sendByTemplate/" + phone,
method: "post",
});
};
/**
* 注册
* @param data
*/
export const register = (data: API.PhoneRegisterRequest) => {
return web.request({
url: "/auth/user/register",
method: "post",
data: data,
});
};

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="#ea580c" d="M11.984 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12a12 12 0 0 0 12-12A12 12 0 0 0 12 0zm6.09 5.333c.328 0 .593.266.592.593v1.482a.594.594 0 0 1-.593.592H9.777c-.982 0-1.778.796-1.778 1.778v5.63c0 .327.266.592.593.592h5.63c.982 0 1.778-.796 1.778-1.778v-.296a.593.593 0 0 0-.592-.593h-4.15a.59.59 0 0 1-.592-.592v-1.482a.593.593 0 0 1 .593-.592h6.815c.327 0 .593.265.593.592v3.408a4 4 0 0 1-4 4H5.926a.593.593 0 0 1-.593-.593V9.778a4.444 4.444 0 0 1 4.445-4.444h8.296Z"/></svg>

After

Width:  |  Height:  |  Size: 579 B

View File

@@ -5,7 +5,7 @@ import "./index.less";
import { useNavigate, useSearchParams } from "react-router-dom";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
import localforage from "localforage";
import { setStorage } from "@/utils/localStorage/config.ts";
const LoadingPage = () => {
const [search] = useSearchParams();
@@ -15,7 +15,7 @@ const LoadingPage = () => {
const store = useStore("user");
store.setToken(token);
store.setUserId(userId);
localforage.setItem("token", token).then();
setStorage("token", token, 24 * 60 * 30);
useEffect(() => {
document.body.classList.add("loading-body");
if (store.getToken() !== null && store.getUserId() !== null) {

View File

@@ -10,7 +10,7 @@ import {
useNavigate,
useRoutes,
} from "react-router-dom";
import localforage from "localforage";
import { getStorageFromKey } from "@/utils/localStorage/config.ts";
//递归查询对应的路由
export function searchRouteDetail(path: string, routes: RouteObject[]): RouteObject | null {
@@ -28,21 +28,21 @@ async function guard(location: Location, navigate: NavigateFunction, routes: Rou
const { pathname } = location;
//找到对应的路由信息
const routedetail: RouteObject | null = searchRouteDetail(pathname, routes);
const routerDetail: RouteObject | null = searchRouteDetail(pathname, routes);
//没有找到路由跳转404
if (!routedetail) {
if (!routerDetail) {
navigate("/404");
return false;
}
//如果需要权限验证
if (
routedetail.path !== "/login" &&
routedetail.path !== "/register" &&
routedetail.path !== "/" &&
routedetail.path !== "/404"
routerDetail.path !== "/login" &&
routerDetail.path !== "/register" &&
routerDetail.path !== "/" &&
routerDetail.path !== "/404"
) {
const token: string | null = await localforage.getItem("token");
const token: string | null = getStorageFromKey("token");
if (!token) {
message.warning("请先登录!").then();
navigate("/login");

View File

@@ -1,7 +1,13 @@
// @ts-ignore
/** @format */
/* eslint-disable */
declare namespace API {
type PhoneRegisterRequest = {
phone?: string;
password?: string;
confirmPassword?: string;
activeCode?: string;
};
// type ApiResponse<T> = {
// success?: boolean;
// code?: number;
@@ -124,23 +130,23 @@ declare namespace API {
// type?: NoticeIconItemType;
// };
type GenerateMpRegCode = {
data?: {
regCode?: string;
qrCodeUrl?: string;
expireSeconds?: number;
ticket?: string;
url?: string;
};
}
// type GenerateMpRegCode = {
// data?: {
// regCode?: string;
// qrCodeUrl?: string;
// expireSeconds?: number;
// ticket?: string;
// url?: string;
// };
// }
// type GetClientId = {
// data?: string;
// }
type GenerateBase64Code = {
data?: string;
}
// type GenerateBase64Code = {
// data?: string;
// }
// type GetClientToken = {
// data?: {
@@ -150,14 +156,6 @@ declare namespace API {
// };
// }
type PhoneRegisterRequest = {
clientId?: string;
phone?: string;
password?: string;
confirmPassword?: string;
smsCode?: number;
}
// type PhoneRegisterResponse = ResponseStructure & {
// data?: number;
// }

View File

@@ -2,6 +2,7 @@
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { message } from "antd";
import { getStorageFromKey } from "@/utils/localStorage/config.ts";
class Request {
private instance: AxiosInstance | undefined;
@@ -11,6 +12,11 @@ class Request {
// 全局请求拦截
this.instance.interceptors.request.use(
(config) => {
const token: string | null = getStorageFromKey("token");
if (token) {
config.headers.Authorization = `schisandra ${token}`;
}
// if (config.method == "post") {
// config.data = EncryptData(JSON.stringify(config.data));
// }

View File

@@ -1,17 +1,10 @@
/** @format */
import Request from "./request";
import localforage from "localforage";
async function getToken() {
return await localforage.getItem("token");
}
const token = await getToken();
const web: Request = new Request({
baseURL: import.meta.env.VITE_APP_BASE_API,
headers: {
token: import.meta.env.VITE_APP_TOKEN_KEY + " " + token,
},
timeout: 5000,
});
export default web;

View File

@@ -9,17 +9,23 @@ import {
UserOutlined,
WechatOutlined,
} from "@ant-design/icons";
import { ProFormCaptcha, ProFormCheckbox, ProFormText } from "@ant-design/pro-components";
import { Alert, Button, Divider, Form, Image, message, Space, Tabs } from "antd";
import { CSSProperties, useRef, useState } from "react";
import {
CaptFieldRef,
ProFormCaptcha,
ProFormCheckbox,
ProFormText,
} from "@ant-design/pro-components";
import { Alert, Button, 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 } from "react-rotate-captcha";
import { get, load, verify } from "@/api/captcha/index.ts";
import { oauthLogin } from "@/api/user";
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 useStore from '@/utils/store/useStore.tsx'
type LoginType = "account" | "phone";
@@ -33,6 +39,17 @@ const iconStyles: CSSProperties = {
export default observer(() => {
const [form] = Form.useForm();
const captcha = useRef<CaptchaInstance>(null);
const captchaRef = useRef<CaptFieldRef | null | undefined>();
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: (
@@ -56,15 +73,21 @@ export default observer(() => {
async function oAuthLogin(type: string) {
const res: any = await oauthLogin(type);
console.log(res);
window.location.href = res.data;
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}>
@@ -137,7 +160,7 @@ export default observer(() => {
size: "large",
prefix: <UserOutlined className={"prefixIcon"} />,
}}
placeholder={"请输入账号/邮箱/电话号码"}
placeholder={"请输入邮箱电话号码"}
rules={[
{
required: true,
@@ -165,26 +188,6 @@ export default observer(() => {
},
]}
/>
{/*<ProFormText*/}
{/* addonAfter={CodeImg}*/}
{/* name='code'*/}
{/* fieldProps={{*/}
{/* size: 'large',*/}
{/* prefix: <BarcodeOutlined className={'prefixIcon'} />,*/}
{/* autoComplete: 'off',*/}
{/* }}*/}
{/* placeholder='请输入图形验证码'*/}
{/* rules={[*/}
{/* {*/}
{/* required: true,*/}
{/* message: '请输入图形验证码!',*/}
{/* },*/}
{/* {*/}
{/* pattern: /^[a-zA-Z0-9]{5}$/,*/}
{/* message: '图形验证码格式不正确',*/}
{/* },*/}
{/* ]}*/}
{/*/>*/}
</>
)}
{loginType === "phone" && (
@@ -208,26 +211,6 @@ export default observer(() => {
},
]}
/>
{/*<ProFormText*/}
{/* addonAfter={CodeImg}*/}
{/* name='code'*/}
{/* fieldProps={{*/}
{/* size: 'large',*/}
{/* prefix: <BarcodeOutlined className={'prefixIcon'} />,*/}
{/* autoComplete: 'off',*/}
{/* }}*/}
{/* placeholder='请输入图形验证码'*/}
{/* rules={[*/}
{/* {*/}
{/* required: true,*/}
{/* message: '请输入图形验证码!',*/}
{/* },*/}
{/* {*/}
{/* pattern: /^[a-zA-Z0-9]{5}$/,*/}
{/* message: '图形验证码格式不正确',*/}
{/* },*/}
{/* ]}*/}
{/*/>*/}
<ProFormCaptcha
fieldProps={{
size: "large",
@@ -237,22 +220,30 @@ export default observer(() => {
size: "large",
}}
placeholder={"请输入验证码"}
captchaTextRender={(timing, count) => {
captchaTextRender={(timing: boolean) => {
if (timing) {
return `${count} ${"获取验证码"}`;
// return `${count} ${"获取验证码"}`;
return `${"获取验证码"}`;
}
return "获取验证码";
}}
name="captcha"
phoneName={"mobile"}
rules={[
{
required: true,
message: "请输入验证码!",
},
]}
onGetCaptcha={async () => {
captcha.current!.open();
message.success("获取验证码成功验证码为1234");
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);
}
}}
/>
</>
@@ -271,21 +262,18 @@ export default observer(() => {
onClick={async () => {
let validateFields;
if (loginType === "account") {
validateFields = ["username", "password", "code"];
validateFields = ["username", "password"];
} else {
validateFields = ["mobile", "captcha", "code"];
validateFields = ["mobile", "captcha"];
}
await form
.validateFields(validateFields)
.then(async (values) => {
if (loginType === "account") {
captcha.current!.open();
}
await onSubmit(values as API.PhoneRegisterRequest);
await onSubmit(values);
})
.catch((errorInfo) => {
console.error(errorInfo);
.catch((error) => {
console.error(error);
});
}}>
@@ -320,9 +308,11 @@ export default observer(() => {
border: "1px solid #D4D8DD",
borderRadius: "50%",
}}>
<Tooltip title="QQ登录" color={"blue"}>
<QqOutlined
style={{ ...iconStyles, color: "#1677FF" }}
/>
</Tooltip>
</div>
<div
style={{
@@ -335,9 +325,11 @@ export default observer(() => {
border: "1px solid #D4D8DD",
borderRadius: "50%",
}}>
<Tooltip title="企业微信登录" color={"green"}>
<WechatOutlined
style={{ ...iconStyles, color: "#08a327" }}
/>
</Tooltip>
</div>
<div
style={{
@@ -350,12 +342,14 @@ export default observer(() => {
border: "1px solid #D4D8DD",
borderRadius: "50%",
}}>
<Tooltip title="github登录" color={"black"}>
<GithubOutlined
onClick={() => {
oAuthLogin("github").then();
}}
style={{ ...iconStyles, color: "#333333" }}
/>
</Tooltip>
</div>
<div
style={{
@@ -368,12 +362,14 @@ export default observer(() => {
border: "1px solid #D4D8DD",
borderRadius: "50%",
}}>
<Tooltip title="gitee登录" color={"orange"}>
<GitlabOutlined
onClick={() => {
oAuthLogin("gitee").then();
}}
style={{ ...iconStyles, color: "#FF6A10" }}
/>
</Tooltip>
</div>
</Space>
</div>

View File

@@ -2,7 +2,7 @@
import { LockOutlined, MobileOutlined, WechatOutlined } from "@ant-design/icons";
import { ProFormCaptcha, ProFormText } from "@ant-design/pro-components";
import { Space, Tabs, message, Image, Alert, Form, Button } from "antd";
import { Alert, Button, Form, Image, message, Space, Tabs } from "antd";
import { useState } from "react";
import logo from "@/assets/icons/schisandra.svg";
// import background from '@/assets/images/background.png'
@@ -10,6 +10,7 @@ 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 { getSms, register } from "@/api/user";
// import useStore from '@/utils/store/useStore.tsx'
type LoginType = "phone";
@@ -29,7 +30,12 @@ export default observer(() => {
const [loginType, setLoginType] = useState<LoginType>("phone");
const onSubmit = async (formData: object) => {
console.log(formData);
const res: any = await register(formData);
if (res && res.success) {
message.success(res.data);
} else {
message.error(res.data);
}
};
return (
<div className={styles.container}>
@@ -168,21 +174,28 @@ export default observer(() => {
size: "large",
}}
placeholder={"请输入验证码"}
captchaTextRender={(timing, count) => {
captchaTextRender={(timing: boolean) => {
if (timing) {
return `${count} ${"获取验证码"}`;
return `${"获取验证码"}`;
}
return "获取验证码";
}}
name="captcha"
name="activeCode"
phoneName={"phone"}
countDown={300}
rules={[
{
required: true,
message: "请输入验证码!",
},
]}
onGetCaptcha={async () => {
message.success("获取验证码成功验证码为1234");
onGetCaptcha={async (phone: string) => {
const res: any = await getSms(phone);
if (res && res.success) {
message.success(res.data, 3);
} else {
message.warning(res.data, 3);
}
}}
/>
</>
@@ -193,10 +206,8 @@ export default observer(() => {
onClick={async () => {
const validateFields = [
"phone",
"username",
"password",
"captcha",
"code",
"activeCode",
"confirmPassword",
];
await form
@@ -204,8 +215,8 @@ export default observer(() => {
.then(async (values) => {
await onSubmit(values as API.PhoneRegisterRequest);
})
.catch((errorInfo) => {
console.error(errorInfo);
.catch((error) => {
console.error(error);
});
}}>

View File

@@ -2,10 +2,10 @@
import { defineConfig, loadEnv } from "vite";
import react from "@vitejs/plugin-react";
import * as path from "path";
import { resolve } from "path";
// icons plugin
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import * as path from "path";
import imagemin from "unplugin-imagemin/vite";
import viteCompression from "vite-plugin-compression";
import { createHtmlPlugin } from "vite-plugin-html";