fix: 旋转图片验证对接完成
This commit is contained in:
@@ -7,7 +7,7 @@ VITE_APP_BASE_API='/api'
|
|||||||
VITE_APP_TITLE=生产环境
|
VITE_APP_TITLE=生产环境
|
||||||
|
|
||||||
# 网络请求公用地址
|
# 网络请求公用地址
|
||||||
VITE_API_BASE_URL=''
|
VITE_API_BASE_URL='http://1.95.0.111:3000'
|
||||||
|
|
||||||
VITE_TITLE_NAME='五味子云存储'
|
VITE_TITLE_NAME='五味子云存储'
|
||||||
|
|
||||||
@@ -15,4 +15,4 @@ VITE_TITLE_NAME='五味子云存储'
|
|||||||
VITE_APP_TOKEN_KEY='token'
|
VITE_APP_TOKEN_KEY='token'
|
||||||
|
|
||||||
# the upload url
|
# the upload url
|
||||||
VITE_UPLOAD_URL='http://127.0.0.1:3000'
|
VITE_UPLOAD_URL='http://1.95.0.111:4000'
|
||||||
|
50
package.json
50
package.json
@@ -10,27 +10,27 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.3.6",
|
"@ant-design/icons": "^5.3.7",
|
||||||
"@ant-design/pro-components": "^2.7.0",
|
"@ant-design/pro-components": "^2.7.1",
|
||||||
"@ant-design/use-emotion-css": "^1.0.4",
|
"@ant-design/use-emotion-css": "^1.0.4",
|
||||||
"@babel/preset-env": "^7.24.5",
|
"@babel/preset-env": "^7.24.5",
|
||||||
"@types/crypto-js": "^4.2.2",
|
"@types/crypto-js": "^4.2.2",
|
||||||
"@vitejs/plugin-legacy": "^5.3.2",
|
"@vitejs/plugin-legacy": "^5.4.0",
|
||||||
"antd": "^5.16.1",
|
"antd": "^5.17.0",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
"core-js": "3",
|
"core-js": "^3.37.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"gsap": "^3.12.5",
|
"gsap": "^3.12.5",
|
||||||
"jsencrypt": "^3.3.2",
|
"jsencrypt": "^3.3.2",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"mobx": "^6.12.3",
|
"mobx": "^6.12.3",
|
||||||
"mobx-persist-store": "^1.1.4",
|
"mobx-persist-store": "^1.1.5",
|
||||||
"mobx-react": "^9.1.1",
|
"mobx-react": "^9.1.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-rotate-captcha": "^1.0.26",
|
"react-rotate-captcha": "^1.0.26",
|
||||||
"react-router-dom": "^6.22.3",
|
"react-router-dom": "^6.23.0",
|
||||||
"regenerator-runtime": "^0.14.1",
|
"regenerator-runtime": "^0.14.1",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"vite-plugin-compression": "^0.5.1",
|
||||||
"vite-plugin-html": "^3.2.2",
|
"vite-plugin-html": "^3.2.2",
|
||||||
@@ -39,28 +39,28 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-babel": "^6.0.4",
|
"@rollup/plugin-babel": "^6.0.4",
|
||||||
"@types/gsap": "^3.0.0",
|
"@types/gsap": "^3.0.0",
|
||||||
"@types/node": "^20.11.30",
|
"@types/node": "^20.12.11",
|
||||||
"@types/react": "^18.2.69",
|
"@types/react": "^18.3.1",
|
||||||
"@types/react-dom": "^18.2.22",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||||
"@typescript-eslint/parser": "^7.3.1",
|
"@typescript-eslint/parser": "^7.8.0",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-prettier": "^5.1.3",
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
"eslint-plugin-react": "^7.34.1",
|
"eslint-plugin-react": "^7.34.1",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.6",
|
"eslint-plugin-react-refresh": "^0.4.6",
|
||||||
"less": "^4.2.0",
|
"less": "^4.2.0",
|
||||||
"postcss-less": "^6.0.0",
|
"postcss-less": "^6.0.0",
|
||||||
"postcss-preset-env": "^9.5.9",
|
"postcss-preset-env": "^9.5.11",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"stylelint": "^16.2.1",
|
"stylelint": "^16.5.0",
|
||||||
"stylelint-config-recess-order": "^5.0.0",
|
"stylelint-config-recess-order": "^5.0.1",
|
||||||
"stylelint-config-standard-less": "^3.0.1",
|
"stylelint-config-standard-less": "^3.0.1",
|
||||||
"stylelint-order": "^6.0.4",
|
"stylelint-order": "^6.0.4",
|
||||||
"typescript": "^5.4.3",
|
"typescript": "^5.4.5",
|
||||||
"unplugin-imagemin": "^0.5.18",
|
"unplugin-imagemin": "^0.5.18",
|
||||||
"vite": "^5.2.3"
|
"vite": "^5.2.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
481
pnpm-lock.yaml
generated
481
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
16
src/api/captcha/api.ts
Normal file
16
src/api/captcha/api.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import web from '@/utils/axios/web.ts'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验证码
|
||||||
|
*/
|
||||||
|
export const getCaptcha = () => {
|
||||||
|
return web.post('/ReactRotateCaptcha/get')
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 验证验证码
|
||||||
|
* @param data
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
export const VerfiyCaptcha = (data: any) => {
|
||||||
|
return web.post('/ReactRotateCaptcha/verfiy', data)
|
||||||
|
}
|
@@ -1,51 +1,14 @@
|
|||||||
import type { TicketInfoType, TokenInfoType } from 'react-rotate-captcha'
|
import type { TicketInfoType, TokenInfoType } from 'react-rotate-captcha'
|
||||||
import { handle } from './canvas'
|
import { getCaptcha, VerfiyCaptcha } from '@/api/captcha/api.ts'
|
||||||
import wallhaven from '@/assets/images/wallhaven.jpg'
|
|
||||||
export type ActionType = {
|
export type ActionType = {
|
||||||
code: 0 | 1
|
code: 0 | 1
|
||||||
msg: string
|
msg: string
|
||||||
}
|
}
|
||||||
|
let image: string = ''
|
||||||
const tokenRaw = 'Nvuv8LdXUNRAVW022Gm7HkGc7RTDoEmU'
|
|
||||||
const info = {
|
|
||||||
angle: -1,
|
|
||||||
sid: '',
|
|
||||||
ticket: '',
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function checkTicket(ticket?: TicketInfoType) {
|
|
||||||
const { sid, ticket: ticketRaw } = info
|
|
||||||
const { data } = ticket || {}
|
|
||||||
|
|
||||||
const isWait = sid !== '' && ticketRaw !== ''
|
|
||||||
const success = sid === data?.sid && ticketRaw === data.ticket
|
|
||||||
|
|
||||||
const result =
|
|
||||||
isWait && success
|
|
||||||
? {
|
|
||||||
code: 0,
|
|
||||||
msg: 'Successful',
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
code: 1,
|
|
||||||
msg: 'Failed',
|
|
||||||
}
|
|
||||||
|
|
||||||
return result as ActionType
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function get(): Promise<TokenInfoType> {
|
export async function get(): Promise<TokenInfoType> {
|
||||||
info.angle = -1
|
const res: any = await getCaptcha()
|
||||||
info.sid = ''
|
image = res.data.str
|
||||||
info.ticket = ''
|
return res
|
||||||
return {
|
|
||||||
code: 0,
|
|
||||||
data: {
|
|
||||||
str: 'wallhaven1',
|
|
||||||
token: tokenRaw,
|
|
||||||
},
|
|
||||||
msg: 'success',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isSupportWebp() {
|
export function isSupportWebp() {
|
||||||
@@ -62,10 +25,7 @@ export function isSupportWebp() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function load() {
|
export async function load() {
|
||||||
const [degree, src] = await handle(wallhaven)
|
return image
|
||||||
info.angle = degree
|
|
||||||
console.log('degree', degree)
|
|
||||||
return src
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sleep(time: number) {
|
export function sleep(time: number) {
|
||||||
@@ -75,25 +35,10 @@ export function sleep(time: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function verify(token: string, deg: number): Promise<TicketInfoType> {
|
export async function verify(token: string, deg: number): Promise<TicketInfoType> {
|
||||||
console.log(deg)
|
const data: any = {
|
||||||
console.log(info.angle)
|
token: token,
|
||||||
const { angle } = info
|
deg: deg,
|
||||||
const success = token === tokenRaw && Math.abs(deg - angle) <= 5
|
}
|
||||||
|
const res: any = await VerfiyCaptcha(data)
|
||||||
info.sid = Math.random().toString(36).slice(-8)
|
return res
|
||||||
// info.ticket = crypto.randomUUID()
|
|
||||||
|
|
||||||
return angle >= 0 && success
|
|
||||||
? {
|
|
||||||
code: 0,
|
|
||||||
data: {
|
|
||||||
sid: info.sid,
|
|
||||||
ticket: info.ticket,
|
|
||||||
},
|
|
||||||
msg: 'Success',
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
code: 1,
|
|
||||||
msg: 'Fail verify',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1 @@
|
|||||||
import web from '@/utils/axios/web.ts'
|
|
||||||
|
|
||||||
export const getPublicKey = () => {
|
|
||||||
return web.get('/encrypt/getPublicKey')
|
|
||||||
}
|
|
||||||
|
@@ -4,197 +4,197 @@ import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
|||||||
import './index.less'
|
import './index.less'
|
||||||
import SvgIcon from '@/components/SvgIcon/SvgIcon.tsx'
|
import SvgIcon from '@/components/SvgIcon/SvgIcon.tsx'
|
||||||
const HomeIndex: React.FC = () => {
|
const HomeIndex: React.FC = () => {
|
||||||
const animationFunction=()=>{
|
const animationFunction = () => {
|
||||||
if (!CSS.supports('animation-timeline: scroll()')) {
|
if (!CSS.supports('animation-timeline: scroll()')) {
|
||||||
// const SPAN = 'max(45vw, 260px)';
|
// const SPAN = 'max(45vw, 260px)';
|
||||||
const CONFIG = [
|
const CONFIG = [
|
||||||
{
|
{
|
||||||
x: () => {
|
x: () => {
|
||||||
return Math.max(260, window.innerWidth * 0.45) * -1
|
return Math.max(260, window.innerWidth * 0.45) * -1
|
||||||
},
|
},
|
||||||
y: -10,
|
y: -10,
|
||||||
r: -8,
|
r: -8,
|
||||||
h: 160,
|
h: 160,
|
||||||
w: (el: any) => {
|
w: (el: any) => {
|
||||||
return Math.max(320, el.parentNode.offsetWidth * 0.55)
|
return Math.max(320, el.parentNode.offsetWidth * 0.55)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
x: () => {
|
x: () => {
|
||||||
return Math.max(260, window.innerWidth * 0.45)
|
return Math.max(260, window.innerWidth * 0.45)
|
||||||
},
|
},
|
||||||
y: -50,
|
y: -50,
|
||||||
r: 15,
|
r: 15,
|
||||||
h: 360,
|
h: 360,
|
||||||
w: (el: any) => {
|
w: (el: any) => {
|
||||||
return Math.max(220, el.parentNode.offsetWidth * 0.3)
|
return Math.max(220, el.parentNode.offsetWidth * 0.3)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
x: () => {
|
x: () => {
|
||||||
return Math.max(260, window.innerWidth * 0.45) * -1
|
return Math.max(260, window.innerWidth * 0.45) * -1
|
||||||
},
|
},
|
||||||
y: -30,
|
y: -30,
|
||||||
r: 6,
|
r: 6,
|
||||||
h: 300,
|
h: 300,
|
||||||
w: (el: any) => {
|
w: (el: any) => {
|
||||||
return Math.max(330, el.parentNode.offsetWidth * 0.55)
|
return Math.max(330, el.parentNode.offsetWidth * 0.55)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
x: () => {
|
x: () => {
|
||||||
return Math.max(260, window.innerWidth * 0.45)
|
return Math.max(260, window.innerWidth * 0.45)
|
||||||
},
|
},
|
||||||
y: -30,
|
y: -30,
|
||||||
r: -5,
|
r: -5,
|
||||||
h: 400,
|
h: 400,
|
||||||
w: (el: any) => {
|
w: (el: any) => {
|
||||||
return Math.max(305, el.parentNode.offsetWidth * 0.45)
|
return Math.max(305, el.parentNode.offsetWidth * 0.45)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
x: () => {
|
x: () => {
|
||||||
return Math.max(260, window.innerWidth * 0.45) * -1
|
return Math.max(260, window.innerWidth * 0.45) * -1
|
||||||
},
|
},
|
||||||
y: -45,
|
y: -45,
|
||||||
r: -20,
|
r: -20,
|
||||||
h: 525,
|
h: 525,
|
||||||
w: (el: any) => {
|
w: (el: any) => {
|
||||||
return Math.max(160, el.parentNode.offsetWidth * 0.3)
|
return Math.max(160, el.parentNode.offsetWidth * 0.3)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
x: () => {
|
x: () => {
|
||||||
return Math.max(260, window.innerWidth * 0.45)
|
return Math.max(260, window.innerWidth * 0.45)
|
||||||
},
|
},
|
||||||
y: 10,
|
y: 10,
|
||||||
r: 10,
|
r: 10,
|
||||||
h: 160,
|
h: 160,
|
||||||
w: (el: any) => {
|
w: (el: any) => {
|
||||||
return Math.max(320, el.parentNode.offsetWidth * 0.55)
|
return Math.max(320, el.parentNode.offsetWidth * 0.55)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
gsap.registerPlugin(ScrollTrigger)
|
gsap.registerPlugin(ScrollTrigger)
|
||||||
console.info('gsap: ScrollTrigger registered')
|
console.info('gsap: ScrollTrigger registered')
|
||||||
|
|
||||||
gsap.set('.hero', { position: 'absolute' })
|
gsap.set('.hero', { position: 'absolute' })
|
||||||
|
|
||||||
const cards = document.querySelectorAll('.card')
|
const cards = document.querySelectorAll('.card')
|
||||||
|
|
||||||
for (const [index, card] of [...cards].entries()) {
|
for (const [index, card] of [...cards].entries()) {
|
||||||
if (CONFIG[index]) {
|
if (CONFIG[index]) {
|
||||||
gsap.from(card, {
|
gsap.from(card, {
|
||||||
x: CONFIG[index].x,
|
x: CONFIG[index].x,
|
||||||
yPercent: CONFIG[index].y,
|
yPercent: CONFIG[index].y,
|
||||||
height: `${CONFIG[index].h}%`,
|
height: `${CONFIG[index].h}%`,
|
||||||
rotate: CONFIG[index].r,
|
rotate: CONFIG[index].r,
|
||||||
width: CONFIG[index].w,
|
width: CONFIG[index].w,
|
||||||
scrollTrigger: {
|
scrollTrigger: {
|
||||||
trigger: '.scroller',
|
trigger: '.scroller',
|
||||||
start: 'top bottom',
|
start: 'top bottom',
|
||||||
end: 'top 50%',
|
end: 'top 50%',
|
||||||
scrub: true,
|
scrub: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gsap.from(
|
gsap.from(
|
||||||
[
|
[
|
||||||
'.card__content',
|
'.card__content',
|
||||||
'.card--two .card__column:last-of-type',
|
'.card--two .card__column:last-of-type',
|
||||||
'.card--three .card__column:last-of-type',
|
'.card--three .card__column:last-of-type',
|
||||||
'.card--five .card__column:last-of-type',
|
'.card--five .card__column:last-of-type',
|
||||||
],
|
],
|
||||||
|
|
||||||
{
|
{
|
||||||
y: '-100cqh',
|
y: '-100cqh',
|
||||||
scrollTrigger: {
|
scrollTrigger: {
|
||||||
trigger: '.scroller',
|
trigger: '.scroller',
|
||||||
start: 'top 80%',
|
start: 'top 80%',
|
||||||
end: 'top top',
|
end: 'top top',
|
||||||
scrub: true,
|
scrub: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
gsap.from(['.card__avatar img', '.password svg'], {
|
gsap.from(['.card__avatar img', '.password svg'], {
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
scrollTrigger: {
|
scrollTrigger: {
|
||||||
trigger: '.scroller',
|
trigger: '.scroller',
|
||||||
start: 'top 50%',
|
start: 'top 50%',
|
||||||
end: 'top top',
|
end: 'top top',
|
||||||
scrub: true,
|
scrub: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
gsap.from(['.card--five .card__dummy', '.card--six .card__dummy'], {
|
gsap.from(['.card--five .card__dummy', '.card--six .card__dummy'], {
|
||||||
width: (el: any) => el.parentNode.offsetWidth * 0.26,
|
width: (el: any) => el.parentNode.offsetWidth * 0.26,
|
||||||
scrollTrigger: {
|
scrollTrigger: {
|
||||||
trigger: '.scroller',
|
trigger: '.scroller',
|
||||||
start: 'top 80%',
|
start: 'top 80%',
|
||||||
end: 'top top',
|
end: 'top top',
|
||||||
scrub: true,
|
scrub: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
gsap.from(['.card--one .card__avatar', '.card--four .card__avatar'], {
|
gsap.from(['.card--one .card__avatar', '.card--four .card__avatar'], {
|
||||||
scale: 2,
|
scale: 2,
|
||||||
scrollTrigger: {
|
scrollTrigger: {
|
||||||
trigger: '.scroller',
|
trigger: '.scroller',
|
||||||
start: 'top bottom',
|
start: 'top bottom',
|
||||||
end: 'top top',
|
end: 'top top',
|
||||||
scrub: true,
|
scrub: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
gsap.from('.card--two .card__avatar', {
|
gsap.from('.card--two .card__avatar', {
|
||||||
width: (el: any) => Math.max(330, el.parentNode.offsetWidth * 0.55) - 32,
|
width: (el: any) => Math.max(330, el.parentNode.offsetWidth * 0.55) - 32,
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
height: 'calc(300cqh - 2rem)',
|
height: 'calc(300cqh - 2rem)',
|
||||||
scrollTrigger: {
|
scrollTrigger: {
|
||||||
trigger: '.scroller',
|
trigger: '.scroller',
|
||||||
start: 'top bottom',
|
start: 'top bottom',
|
||||||
end: 'top 20%',
|
end: 'top 20%',
|
||||||
scrub: true,
|
scrub: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
gsap.from('.card--six .card__column:last-of-type .card__company', {
|
gsap.from('.card--six .card__column:last-of-type .card__company', {
|
||||||
width: 120,
|
width: 120,
|
||||||
x: '-1rem',
|
x: '-1rem',
|
||||||
scrollTrigger: {
|
scrollTrigger: {
|
||||||
trigger: '.scroller',
|
trigger: '.scroller',
|
||||||
start: 'top bottom',
|
start: 'top bottom',
|
||||||
end: 'top 20%',
|
end: 'top 20%',
|
||||||
scrub: true,
|
scrub: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
gsap.from('.cta', {
|
gsap.from('.cta', {
|
||||||
scale: 1,
|
scale: 1,
|
||||||
scrollTrigger: {
|
scrollTrigger: {
|
||||||
trigger: '.scroller',
|
trigger: '.scroller',
|
||||||
start: 'top bottom',
|
start: 'top bottom',
|
||||||
end: 'top 20%',
|
end: 'top 20%',
|
||||||
scrub: true,
|
scrub: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.body.classList.add('body')
|
document.body.classList.add('body')
|
||||||
window.addEventListener('resize', animationFunction);
|
window.addEventListener('resize', animationFunction)
|
||||||
return () => {
|
return () => {
|
||||||
document.body.classList.remove('body')
|
document.body.classList.remove('body')
|
||||||
window.removeEventListener('resize', animationFunction);
|
window.removeEventListener('resize', animationFunction)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
|
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
|
||||||
import './assets/styles/index.less'
|
import './assets/styles/index.less'
|
||||||
@@ -8,9 +8,9 @@ import { Provider as MobxProvider } from 'mobx-react'
|
|||||||
import { RootStore } from '@/store'
|
import { RootStore } from '@/store'
|
||||||
const router = createBrowserRouter(routeConfig)
|
const router = createBrowserRouter(routeConfig)
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
// <React.StrictMode>
|
<React.StrictMode>
|
||||||
<MobxProvider {...RootStore}>
|
<MobxProvider {...RootStore}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
</MobxProvider>,
|
</MobxProvider>,
|
||||||
// </React.StrictMode>,
|
</React.StrictMode>,
|
||||||
)
|
)
|
||||||
|
@@ -18,10 +18,10 @@ class Request {
|
|||||||
// 全局响应拦截
|
// 全局响应拦截
|
||||||
this.instance.interceptors.response.use(
|
this.instance.interceptors.response.use(
|
||||||
(res) => {
|
(res) => {
|
||||||
if (res.data.code && res.data.code !== 200) {
|
// if (res.data.code && res.data.code !== 200) {
|
||||||
message.error(res.data.message).then()
|
// message.error(res.data.message).then()
|
||||||
return Promise.reject(res.data)
|
// return Promise.reject(res.data)
|
||||||
}
|
// }
|
||||||
return res.data
|
return res.data
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
|
@@ -9,14 +9,14 @@ import {
|
|||||||
} from '@ant-design/icons'
|
} from '@ant-design/icons'
|
||||||
import { ProFormCaptcha, ProFormCheckbox, ProFormText } from '@ant-design/pro-components'
|
import { ProFormCaptcha, ProFormCheckbox, ProFormText } from '@ant-design/pro-components'
|
||||||
import { Divider, Space, Tabs, message, Image, Alert, Form, Button } from 'antd'
|
import { Divider, Space, Tabs, message, Image, Alert, Form, Button } from 'antd'
|
||||||
import { CSSProperties } from 'react'
|
import { CSSProperties, useRef } from 'react'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import logo from '@/assets/icons/schisandra.svg'
|
import logo from '@/assets/icons/schisandra.svg'
|
||||||
import qrCode from '@/assets/images/login_qrcode-landaiqing.jpg'
|
import qrCode from '@/assets/images/login_qrcode-landaiqing.jpg'
|
||||||
import styles from './index.module.less'
|
import styles from './index.module.less'
|
||||||
import { observer } from 'mobx-react'
|
import { observer } from 'mobx-react'
|
||||||
import FooterComponent from '@/components/Footer'
|
import FooterComponent from '@/components/Footer'
|
||||||
import RotateCaptcha from 'react-rotate-captcha'
|
import RotateCaptcha, { CaptchaInstance } from 'react-rotate-captcha'
|
||||||
import { get, load, verify } from '@/api/captcha/index.ts'
|
import { get, load, verify } from '@/api/captcha/index.ts'
|
||||||
// import useStore from '@/utils/store/useStore.tsx'
|
// import useStore from '@/utils/store/useStore.tsx'
|
||||||
type LoginType = 'account' | 'phone'
|
type LoginType = 'account' | 'phone'
|
||||||
@@ -30,8 +30,7 @@ const iconStyles: CSSProperties = {
|
|||||||
|
|
||||||
export default observer(() => {
|
export default observer(() => {
|
||||||
const [form] = Form.useForm()
|
const [form] = Form.useForm()
|
||||||
const [open, setOpen] = useState(false)
|
const captcha = useRef<CaptchaInstance>(null)
|
||||||
|
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
@@ -58,322 +57,320 @@ export default observer(() => {
|
|||||||
console.log(formData)
|
console.log(formData)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<RotateCaptcha get={get} load={load} verify={verify} limit={2} ref={captcha}>
|
||||||
<div className={styles.content}>
|
<div className={styles.container}>
|
||||||
<Space className={styles.content_content}>
|
<div className={styles.content}>
|
||||||
<Space className={styles.login_content}>
|
<Space className={styles.content_content}>
|
||||||
<Space align='center' className={styles.mp_code}>
|
<Space className={styles.login_content}>
|
||||||
<Space direction='vertical' align='center'>
|
<Space align='center' className={styles.mp_code}>
|
||||||
<span className={styles.mp_code_title}>微信扫码登录</span>
|
<Space direction='vertical' align='center'>
|
||||||
<Image
|
<span className={styles.mp_code_title}>微信扫码登录</span>
|
||||||
preview={false}
|
<Image
|
||||||
height={210}
|
preview={false}
|
||||||
width={200}
|
height={210}
|
||||||
className={styles.mp_code_img}
|
width={200}
|
||||||
// src={generateMpRegCodeData.data?.qrCodeUrl}
|
className={styles.mp_code_img}
|
||||||
src={qrCode}
|
// src={generateMpRegCodeData.data?.qrCodeUrl}
|
||||||
/>
|
src={qrCode}
|
||||||
<Alert
|
/>
|
||||||
// message={(<span>微信扫码<span>关注公众号</span></span>)}
|
<Alert
|
||||||
description={
|
// message={(<span>微信扫码<span>关注公众号</span></span>)}
|
||||||
<div>
|
description={
|
||||||
<span>
|
<div>
|
||||||
微信扫码
|
<span>
|
||||||
<span className={styles.mp_tips}>关注公众号</span>
|
微信扫码
|
||||||
</span>
|
<span className={styles.mp_tips}>
|
||||||
<br />
|
关注公众号
|
||||||
登录更快更安全
|
</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位字符,且必须包含字母和数字!',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
{/*<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' && (
|
||||||
|
<>
|
||||||
|
<ProFormText
|
||||||
|
fieldProps={{
|
||||||
|
size: 'large',
|
||||||
|
prefix: <MobileOutlined className={'prefixIcon'} />,
|
||||||
|
autoComplete: 'off',
|
||||||
|
}}
|
||||||
|
name='mobile'
|
||||||
|
placeholder={'请输入手机号'}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入手机号!',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /^1\d{10}$/,
|
||||||
|
message: '手机号格式错误!',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
{/*<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',
|
||||||
|
prefix: <LockOutlined className={'prefixIcon'} />,
|
||||||
|
}}
|
||||||
|
captchaProps={{
|
||||||
|
size: 'large',
|
||||||
|
}}
|
||||||
|
placeholder={'请输入验证码'}
|
||||||
|
captchaTextRender={(timing, count) => {
|
||||||
|
if (timing) {
|
||||||
|
return `${count} ${'获取验证码'}`
|
||||||
|
}
|
||||||
|
return '获取验证码'
|
||||||
|
}}
|
||||||
|
name='captcha'
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入验证码!',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
onGetCaptcha={async () => {
|
||||||
|
captcha.current!.open()
|
||||||
|
message.success('获取验证码成功!验证码为:1234')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<div style={{ marginBlockEnd: 14 }}>
|
||||||
|
<ProFormCheckbox noStyle name='autoLogin'>
|
||||||
|
自动登录
|
||||||
|
</ProFormCheckbox>
|
||||||
|
<a style={{ float: 'right' }}>忘记密码 </a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type='primary'
|
||||||
|
block
|
||||||
|
size='large'
|
||||||
|
onClick={async () => {
|
||||||
|
let validateFields
|
||||||
|
if (loginType === 'account') {
|
||||||
|
validateFields = ['username', 'password', 'code']
|
||||||
|
} else {
|
||||||
|
validateFields = ['mobile', 'captcha', 'code']
|
||||||
|
}
|
||||||
|
|
||||||
|
await form
|
||||||
|
.validateFields(validateFields)
|
||||||
|
.then(async (values) => {
|
||||||
|
if (loginType === 'account') {
|
||||||
|
captcha.current!.open()
|
||||||
|
}
|
||||||
|
await onSubmit(values as API.PhoneRegisterRequest)
|
||||||
|
})
|
||||||
|
.catch((errorInfo) => {
|
||||||
|
console.error(errorInfo)
|
||||||
|
})
|
||||||
|
}}>
|
||||||
|
登录
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<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%',
|
||||||
|
}}>
|
||||||
|
<QqOutlined
|
||||||
|
style={{ ...iconStyles, color: '#1677FF' }}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
<div
|
||||||
// type="success"
|
style={{
|
||||||
showIcon={true}
|
display: 'flex',
|
||||||
className={styles.alert}
|
justifyContent: 'center',
|
||||||
icon={<WechatOutlined />}
|
alignItems: 'center',
|
||||||
/>
|
flexDirection: 'column',
|
||||||
</Space>
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
border: '1px solid #D4D8DD',
|
||||||
|
borderRadius: '50%',
|
||||||
|
}}>
|
||||||
|
<WechatOutlined
|
||||||
|
style={{ ...iconStyles, color: '#08a327' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
border: '1px solid #D4D8DD',
|
||||||
|
borderRadius: '50%',
|
||||||
|
}}>
|
||||||
|
<GithubOutlined
|
||||||
|
style={{ ...iconStyles, color: '#333333' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexDirection: 'column',
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
border: '1px solid #D4D8DD',
|
||||||
|
borderRadius: '50%',
|
||||||
|
}}>
|
||||||
|
<GitlabOutlined
|
||||||
|
style={{ ...iconStyles, color: '#FF6A10' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
<a href='/register' className={styles.go_to_register}>
|
||||||
|
<span>注册</span>
|
||||||
|
</a>
|
||||||
</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位字符,且必须包含字母和数字!',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
{/*<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' && (
|
|
||||||
<>
|
|
||||||
<ProFormText
|
|
||||||
fieldProps={{
|
|
||||||
size: 'large',
|
|
||||||
prefix: <MobileOutlined className={'prefixIcon'} />,
|
|
||||||
autoComplete: 'off',
|
|
||||||
}}
|
|
||||||
name='mobile'
|
|
||||||
placeholder={'请输入手机号'}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入手机号!',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: /^1\d{10}$/,
|
|
||||||
message: '手机号格式错误!',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
{/*<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',
|
|
||||||
prefix: <LockOutlined className={'prefixIcon'} />,
|
|
||||||
}}
|
|
||||||
captchaProps={{
|
|
||||||
size: 'large',
|
|
||||||
}}
|
|
||||||
placeholder={'请输入验证码'}
|
|
||||||
captchaTextRender={(timing, count) => {
|
|
||||||
if (timing) {
|
|
||||||
return `${count} ${'获取验证码'}`
|
|
||||||
}
|
|
||||||
return '获取验证码'
|
|
||||||
}}
|
|
||||||
name='captcha'
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入验证码!',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
onGetCaptcha={async () => {
|
|
||||||
message.success('获取验证码成功!验证码为:1234')
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<div style={{ marginBlockEnd: 14 }}>
|
|
||||||
<ProFormCheckbox noStyle name='autoLogin'>
|
|
||||||
自动登录
|
|
||||||
</ProFormCheckbox>
|
|
||||||
<a style={{ float: 'right' }}>忘记密码 </a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type='primary'
|
|
||||||
block
|
|
||||||
size='large'
|
|
||||||
onClick={async () => {
|
|
||||||
setOpen(true)
|
|
||||||
let validateFields
|
|
||||||
if (loginType === 'account') {
|
|
||||||
validateFields = ['username', 'password', 'code']
|
|
||||||
} else {
|
|
||||||
validateFields = ['mobile', 'captcha', 'code']
|
|
||||||
}
|
|
||||||
|
|
||||||
await form
|
|
||||||
.validateFields(validateFields)
|
|
||||||
.then(async (values) => {
|
|
||||||
await onSubmit(values as API.PhoneRegisterRequest)
|
|
||||||
})
|
|
||||||
.catch((errorInfo) => {
|
|
||||||
console.error(errorInfo)
|
|
||||||
})
|
|
||||||
}}>
|
|
||||||
登录
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<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%',
|
|
||||||
}}>
|
|
||||||
<QqOutlined style={{ ...iconStyles, color: '#1677FF' }} />
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
height: 40,
|
|
||||||
width: 40,
|
|
||||||
border: '1px solid #D4D8DD',
|
|
||||||
borderRadius: '50%',
|
|
||||||
}}>
|
|
||||||
<WechatOutlined
|
|
||||||
style={{ ...iconStyles, color: '#08a327' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
height: 40,
|
|
||||||
width: 40,
|
|
||||||
border: '1px solid #D4D8DD',
|
|
||||||
borderRadius: '50%',
|
|
||||||
}}>
|
|
||||||
<GithubOutlined
|
|
||||||
style={{ ...iconStyles, color: '#333333' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
height: 40,
|
|
||||||
width: 40,
|
|
||||||
border: '1px solid #D4D8DD',
|
|
||||||
borderRadius: '50%',
|
|
||||||
}}>
|
|
||||||
<GitlabOutlined
|
|
||||||
style={{ ...iconStyles, color: '#FF6A10' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
<a href='/register' className={styles.go_to_register}>
|
|
||||||
<span>注册</span>
|
|
||||||
</a>
|
|
||||||
</Space>
|
</Space>
|
||||||
</Space>
|
</div>
|
||||||
|
<FooterComponent></FooterComponent>
|
||||||
</div>
|
</div>
|
||||||
<FooterComponent></FooterComponent>
|
</RotateCaptcha>
|
||||||
<RotateCaptcha
|
|
||||||
get={get}
|
|
||||||
load={load}
|
|
||||||
verify={verify}
|
|
||||||
limit={3}
|
|
||||||
result={(val) => {
|
|
||||||
console.log(val)
|
|
||||||
}}
|
|
||||||
open={open}
|
|
||||||
onClose={() => setOpen(false)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@@ -149,7 +149,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
esbuild: {
|
esbuild: {
|
||||||
drop: ['console', 'debugger'],
|
// drop: ['console', 'debugger'],
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: 'dist', // 指定输出路径
|
outDir: 'dist', // 指定输出路径
|
||||||
|
Reference in New Issue
Block a user