fix: 旋转图片验证对接完成
This commit is contained in:
@@ -7,7 +7,7 @@ VITE_APP_BASE_API='/api'
|
||||
VITE_APP_TITLE=生产环境
|
||||
|
||||
# 网络请求公用地址
|
||||
VITE_API_BASE_URL=''
|
||||
VITE_API_BASE_URL='http://1.95.0.111:3000'
|
||||
|
||||
VITE_TITLE_NAME='五味子云存储'
|
||||
|
||||
@@ -15,4 +15,4 @@ VITE_TITLE_NAME='五味子云存储'
|
||||
VITE_APP_TOKEN_KEY='token'
|
||||
|
||||
# the upload url
|
||||
VITE_UPLOAD_URL='http://127.0.0.1:3000'
|
||||
VITE_UPLOAD_URL='http://1.95.0.111:4000'
|
||||
|
38
package.json
38
package.json
@@ -10,27 +10,27 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.3.6",
|
||||
"@ant-design/pro-components": "^2.7.0",
|
||||
"@ant-design/icons": "^5.3.7",
|
||||
"@ant-design/pro-components": "^2.7.1",
|
||||
"@ant-design/use-emotion-css": "^1.0.4",
|
||||
"@babel/preset-env": "^7.24.5",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@vitejs/plugin-legacy": "^5.3.2",
|
||||
"antd": "^5.16.1",
|
||||
"@vitejs/plugin-legacy": "^5.4.0",
|
||||
"antd": "^5.17.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"axios": "^1.6.8",
|
||||
"core-js": "3",
|
||||
"core-js": "^3.37.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"gsap": "^3.12.5",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"localforage": "^1.10.0",
|
||||
"mobx": "^6.12.3",
|
||||
"mobx-persist-store": "^1.1.4",
|
||||
"mobx-persist-store": "^1.1.5",
|
||||
"mobx-react": "^9.1.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-rotate-captcha": "^1.0.26",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"react-router-dom": "^6.23.0",
|
||||
"regenerator-runtime": "^0.14.1",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
@@ -39,11 +39,11 @@
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@types/gsap": "^3.0.0",
|
||||
"@types/node": "^20.11.30",
|
||||
"@types/react": "^18.2.69",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||
"@typescript-eslint/parser": "^7.3.1",
|
||||
"@types/node": "^20.12.11",
|
||||
"@types/react": "^18.3.1",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||
"@typescript-eslint/parser": "^7.8.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
@@ -53,14 +53,14 @@
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"less": "^4.2.0",
|
||||
"postcss-less": "^6.0.0",
|
||||
"postcss-preset-env": "^9.5.9",
|
||||
"postcss-preset-env": "^9.5.11",
|
||||
"prettier": "^3.2.5",
|
||||
"stylelint": "^16.2.1",
|
||||
"stylelint-config-recess-order": "^5.0.0",
|
||||
"stylelint": "^16.5.0",
|
||||
"stylelint-config-recess-order": "^5.0.1",
|
||||
"stylelint-config-standard-less": "^3.0.1",
|
||||
"stylelint-order": "^6.0.4",
|
||||
"typescript": "^5.4.3",
|
||||
"typescript": "^5.4.5",
|
||||
"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 { handle } from './canvas'
|
||||
import wallhaven from '@/assets/images/wallhaven.jpg'
|
||||
import { getCaptcha, VerfiyCaptcha } from '@/api/captcha/api.ts'
|
||||
export type ActionType = {
|
||||
code: 0 | 1
|
||||
msg: 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
|
||||
}
|
||||
|
||||
let image: string = ''
|
||||
export async function get(): Promise<TokenInfoType> {
|
||||
info.angle = -1
|
||||
info.sid = ''
|
||||
info.ticket = ''
|
||||
return {
|
||||
code: 0,
|
||||
data: {
|
||||
str: 'wallhaven1',
|
||||
token: tokenRaw,
|
||||
},
|
||||
msg: 'success',
|
||||
}
|
||||
const res: any = await getCaptcha()
|
||||
image = res.data.str
|
||||
return res
|
||||
}
|
||||
|
||||
export function isSupportWebp() {
|
||||
@@ -62,10 +25,7 @@ export function isSupportWebp() {
|
||||
}
|
||||
|
||||
export async function load() {
|
||||
const [degree, src] = await handle(wallhaven)
|
||||
info.angle = degree
|
||||
console.log('degree', degree)
|
||||
return src
|
||||
return image
|
||||
}
|
||||
|
||||
export function sleep(time: number) {
|
||||
@@ -75,25 +35,10 @@ export function sleep(time: number) {
|
||||
}
|
||||
|
||||
export async function verify(token: string, deg: number): Promise<TicketInfoType> {
|
||||
console.log(deg)
|
||||
console.log(info.angle)
|
||||
const { angle } = info
|
||||
const success = token === tokenRaw && Math.abs(deg - angle) <= 5
|
||||
|
||||
info.sid = Math.random().toString(36).slice(-8)
|
||||
// info.ticket = crypto.randomUUID()
|
||||
|
||||
return angle >= 0 && success
|
||||
? {
|
||||
code: 0,
|
||||
data: {
|
||||
sid: info.sid,
|
||||
ticket: info.ticket,
|
||||
},
|
||||
msg: 'Success',
|
||||
}
|
||||
: {
|
||||
code: 1,
|
||||
msg: 'Fail verify',
|
||||
const data: any = {
|
||||
token: token,
|
||||
deg: deg,
|
||||
}
|
||||
const res: any = await VerfiyCaptcha(data)
|
||||
return res
|
||||
}
|
||||
|
@@ -1,5 +1 @@
|
||||
import web from '@/utils/axios/web.ts'
|
||||
|
||||
export const getPublicKey = () => {
|
||||
return web.get('/encrypt/getPublicKey')
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
||||
import './index.less'
|
||||
import SvgIcon from '@/components/SvgIcon/SvgIcon.tsx'
|
||||
const HomeIndex: React.FC = () => {
|
||||
const animationFunction=()=>{
|
||||
const animationFunction = () => {
|
||||
if (!CSS.supports('animation-timeline: scroll()')) {
|
||||
// const SPAN = 'max(45vw, 260px)';
|
||||
const CONFIG = [
|
||||
@@ -191,10 +191,10 @@ const HomeIndex: React.FC = () => {
|
||||
}
|
||||
useEffect(() => {
|
||||
document.body.classList.add('body')
|
||||
window.addEventListener('resize', animationFunction);
|
||||
window.addEventListener('resize', animationFunction)
|
||||
return () => {
|
||||
document.body.classList.remove('body')
|
||||
window.removeEventListener('resize', animationFunction);
|
||||
window.removeEventListener('resize', animationFunction)
|
||||
}
|
||||
}, [])
|
||||
return (
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// import React from 'react'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
|
||||
import './assets/styles/index.less'
|
||||
@@ -8,9 +8,9 @@ import { Provider as MobxProvider } from 'mobx-react'
|
||||
import { RootStore } from '@/store'
|
||||
const router = createBrowserRouter(routeConfig)
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
// <React.StrictMode>
|
||||
<React.StrictMode>
|
||||
<MobxProvider {...RootStore}>
|
||||
<RouterProvider router={router} />
|
||||
</MobxProvider>,
|
||||
// </React.StrictMode>,
|
||||
</React.StrictMode>,
|
||||
)
|
||||
|
@@ -18,10 +18,10 @@ class Request {
|
||||
// 全局响应拦截
|
||||
this.instance.interceptors.response.use(
|
||||
(res) => {
|
||||
if (res.data.code && res.data.code !== 200) {
|
||||
message.error(res.data.message).then()
|
||||
return Promise.reject(res.data)
|
||||
}
|
||||
// if (res.data.code && res.data.code !== 200) {
|
||||
// message.error(res.data.message).then()
|
||||
// return Promise.reject(res.data)
|
||||
// }
|
||||
return res.data
|
||||
},
|
||||
(error) => {
|
||||
|
@@ -9,14 +9,14 @@ import {
|
||||
} from '@ant-design/icons'
|
||||
import { ProFormCaptcha, ProFormCheckbox, ProFormText } from '@ant-design/pro-components'
|
||||
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 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 from 'react-rotate-captcha'
|
||||
import RotateCaptcha, { CaptchaInstance } from 'react-rotate-captcha'
|
||||
import { get, load, verify } from '@/api/captcha/index.ts'
|
||||
// import useStore from '@/utils/store/useStore.tsx'
|
||||
type LoginType = 'account' | 'phone'
|
||||
@@ -30,8 +30,7 @@ const iconStyles: CSSProperties = {
|
||||
|
||||
export default observer(() => {
|
||||
const [form] = Form.useForm()
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const captcha = useRef<CaptchaInstance>(null)
|
||||
const items = [
|
||||
{
|
||||
label: (
|
||||
@@ -58,6 +57,7 @@ export default observer(() => {
|
||||
console.log(formData)
|
||||
}
|
||||
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}>
|
||||
@@ -79,7 +79,9 @@ export default observer(() => {
|
||||
<div>
|
||||
<span>
|
||||
微信扫码
|
||||
<span className={styles.mp_tips}>关注公众号</span>
|
||||
<span className={styles.mp_tips}>
|
||||
关注公众号
|
||||
</span>
|
||||
</span>
|
||||
<br />
|
||||
登录更快更安全
|
||||
@@ -240,6 +242,7 @@ export default observer(() => {
|
||||
},
|
||||
]}
|
||||
onGetCaptcha={async () => {
|
||||
captcha.current!.open()
|
||||
message.success('获取验证码成功!验证码为:1234')
|
||||
}}
|
||||
/>
|
||||
@@ -257,7 +260,6 @@ export default observer(() => {
|
||||
block
|
||||
size='large'
|
||||
onClick={async () => {
|
||||
setOpen(true)
|
||||
let validateFields
|
||||
if (loginType === 'account') {
|
||||
validateFields = ['username', 'password', 'code']
|
||||
@@ -268,6 +270,9 @@ export default observer(() => {
|
||||
await form
|
||||
.validateFields(validateFields)
|
||||
.then(async (values) => {
|
||||
if (loginType === 'account') {
|
||||
captcha.current!.open()
|
||||
}
|
||||
await onSubmit(values as API.PhoneRegisterRequest)
|
||||
})
|
||||
.catch((errorInfo) => {
|
||||
@@ -306,7 +311,9 @@ export default observer(() => {
|
||||
border: '1px solid #D4D8DD',
|
||||
borderRadius: '50%',
|
||||
}}>
|
||||
<QqOutlined style={{ ...iconStyles, color: '#1677FF' }} />
|
||||
<QqOutlined
|
||||
style={{ ...iconStyles, color: '#1677FF' }}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
@@ -363,17 +370,7 @@ export default observer(() => {
|
||||
</Space>
|
||||
</div>
|
||||
<FooterComponent></FooterComponent>
|
||||
<RotateCaptcha
|
||||
get={get}
|
||||
load={load}
|
||||
verify={verify}
|
||||
limit={3}
|
||||
result={(val) => {
|
||||
console.log(val)
|
||||
}}
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
</RotateCaptcha>
|
||||
)
|
||||
})
|
||||
|
@@ -149,7 +149,7 @@ export default defineConfig(({ mode }) => {
|
||||
},
|
||||
},
|
||||
esbuild: {
|
||||
drop: ['console', 'debugger'],
|
||||
// drop: ['console', 'debugger'],
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist', // 指定输出路径
|
||||
|
Reference in New Issue
Block a user