login
This commit is contained in:
48
src/components/CaptchaInput/index.less
Normal file
48
src/components/CaptchaInput/index.less
Normal file
@ -0,0 +1,48 @@
|
||||
.captchaContainer {
|
||||
width: 100%;
|
||||
|
||||
:global {
|
||||
.ant-input-affix-wrapper {
|
||||
padding-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.captchaWrapper {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
height: 40px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.captchaImage {
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #d9d9d9;
|
||||
object-fit: contain;
|
||||
background: #fff;
|
||||
|
||||
&:hover {
|
||||
border-color: #40a9ff;
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.refreshIcon {
|
||||
font-size: 16px;
|
||||
color: #1890ff;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
padding: 4px;
|
||||
|
||||
&:hover {
|
||||
color: #40a9ff;
|
||||
transform: rotate(180deg);
|
||||
background: rgba(24, 144, 255, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
72
src/components/CaptchaInput/index.tsx
Normal file
72
src/components/CaptchaInput/index.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
|
||||
import { Input, Spin } from 'antd';
|
||||
import { SafetyOutlined } from '@ant-design/icons';
|
||||
import styles from './index.less';
|
||||
import { getCaptcha } from '@/services/login';
|
||||
|
||||
interface CaptchaInputProps {
|
||||
value?: {
|
||||
captcha: string;
|
||||
captchaToken: string;
|
||||
};
|
||||
onChange?: (value: { captcha: string; captchaToken: string }) => void;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export interface CaptchaInputRef {
|
||||
refresh: () => void;
|
||||
}
|
||||
|
||||
const CaptchaInput = forwardRef((props: CaptchaInputProps, ref) => {
|
||||
const { value, onChange, placeholder = '请输入验证码' } = props;
|
||||
const [imgUrl, setImgUrl] = useState<string>('');
|
||||
const [captchaToken, setCaptchaToken] = useState<string>('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// 获取验证码
|
||||
const fetchCaptcha = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await getCaptcha();
|
||||
if (res?.success) {
|
||||
setImgUrl('data:image/png;base64,' + res.data.base64Image);
|
||||
setCaptchaToken(res.data.code);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取验证码失败:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 组件挂载时获取验证码
|
||||
useEffect(() => {
|
||||
fetchCaptcha();
|
||||
}, []);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
refresh: fetchCaptcha,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className={styles.captchaContainer}>
|
||||
<Input
|
||||
name='captcha'
|
||||
value={value?.captcha}
|
||||
onChange={(e) => onChange?.({ captcha: e.target.value, captchaToken: captchaToken })}
|
||||
placeholder={placeholder}
|
||||
maxLength={4}
|
||||
prefix={<SafetyOutlined style={{ color: '#bfbfbf' }} />}
|
||||
suffix={
|
||||
<div className={styles.captchaWrapper}>
|
||||
{loading ? <Spin size="small" /> : <img src={imgUrl} alt="验证码" className={styles.captchaImage} onClick={fetchCaptcha} />}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
CaptchaInput.displayName = 'CaptchaInput';
|
||||
|
||||
export default CaptchaInput;
|
@ -22,3 +22,9 @@ export async function getLogout() { // 退出登录,注销
|
||||
// params
|
||||
});
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
return request('/api/v1/login/logout', {
|
||||
method: 'post',
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user