This commit is contained in:
lix
2025-06-20 14:55:00 +08:00
parent eb90574c74
commit f2ef1e81c8
20 changed files with 624 additions and 195 deletions

View 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;
}
}
}

View 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;

View File

@ -22,3 +22,9 @@ export async function getLogout() { // 退出登录,注销
// params
});
}
export async function logout() {
return request('/api/v1/login/logout', {
method: 'post',
});
}