|
@@ -1,7 +1,7 @@
|
|
|
import React, { useState, useEffect, useRef } from "react";
|
|
|
import http from '@src/http';
|
|
|
-import { Modal, Image, message } from "antd";
|
|
|
-import { qwGetQrCode, qwCheckLogin } from '@src/http/api';
|
|
|
+import { Modal, Image, message, Input, Button } from "antd";
|
|
|
+import { qwGetQrCode, qwCheckLogin, qwCheckQRCode } from '@src/http/api';
|
|
|
|
|
|
interface QrCodeData {
|
|
|
qrcode: string;
|
|
@@ -11,7 +11,7 @@ interface QrCodeData {
|
|
|
}
|
|
|
|
|
|
interface LoginStatusData {
|
|
|
- loginStatus: number; // 0: 代表登录进行中,1: 代表成功,-1: 输入验证码
|
|
|
+ loginStatus: number; // 0代表登录进行中,1代表成功,-1弹出验证码输入框
|
|
|
message: string;
|
|
|
}
|
|
|
|
|
@@ -37,7 +37,10 @@ const QrCodeModal: React.FC<QrCodeModalProps> = ({
|
|
|
const [countdown, setCountdown] = useState<number>(0);
|
|
|
const [loginStatus, setLoginStatus] = useState<number>(0); // 登录状态
|
|
|
const [loginMessage, setLoginMessage] = useState<string>(""); // 登录状态描述
|
|
|
-
|
|
|
+ const [verifyModalVisible, setVerifyModalVisible] = useState(false); // 验证码输入弹窗
|
|
|
+ const [verifyCode, setVerifyCode] = useState(""); // 验证码
|
|
|
+ const [verifyLoading, setVerifyLoading] = useState(false); // 验证码提交加载状态
|
|
|
+
|
|
|
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
|
|
const pollTimerRef = useRef<NodeJS.Timeout | null>(null); // 轮询定时器
|
|
|
|
|
@@ -48,7 +51,8 @@ const QrCodeModal: React.FC<QrCodeModalProps> = ({
|
|
|
// 重置登录状态
|
|
|
setLoginStatus(0);
|
|
|
setLoginMessage("");
|
|
|
-
|
|
|
+ setVerifyCode("");
|
|
|
+
|
|
|
// 根据是否有 vid 参数决定是添加账号还是登录
|
|
|
const res = await http.post<QrCodeData>(qwGetQrCode, { vid });
|
|
|
|
|
@@ -60,7 +64,7 @@ const QrCodeModal: React.FC<QrCodeModalProps> = ({
|
|
|
if (onSuccess) {
|
|
|
onSuccess(res.data);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 开始轮询登录状态
|
|
|
startPollingLoginStatus(res.data.uuid);
|
|
|
} else {
|
|
@@ -81,42 +85,78 @@ const QrCodeModal: React.FC<QrCodeModalProps> = ({
|
|
|
pollTimerRef.current = null;
|
|
|
}
|
|
|
|
|
|
- // 设置轮询间隔为2秒
|
|
|
+ // 设置轮询间隔为3秒
|
|
|
pollTimerRef.current = setInterval(async () => {
|
|
|
try {
|
|
|
const res = await http.post<LoginStatusData>(qwCheckLogin, { uuid });
|
|
|
-
|
|
|
if (res.success) {
|
|
|
const { loginStatus, message: loginMsg } = res.data;
|
|
|
setLoginStatus(loginStatus);
|
|
|
setLoginMessage(loginMsg || "");
|
|
|
-
|
|
|
- // 登录成功或失败时停止轮询
|
|
|
- if (loginStatus !== 0) {
|
|
|
+
|
|
|
+ // 只有登录成功时停止轮询
|
|
|
+ if (loginStatus === 1) {
|
|
|
if (pollTimerRef.current) {
|
|
|
clearInterval(pollTimerRef.current);
|
|
|
pollTimerRef.current = null;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 登录成功
|
|
|
- if (loginStatus === 1) {
|
|
|
- message.success(loginMsg || "登录成功");
|
|
|
- if (onLoginSuccess) {
|
|
|
- onLoginSuccess();
|
|
|
- }
|
|
|
- // 关闭弹窗
|
|
|
- handleClose();
|
|
|
- }
|
|
|
- // 登录失败
|
|
|
- else if (loginStatus === -1) {
|
|
|
- message.error(loginMsg || "登录失败");
|
|
|
+ message.success(loginMsg || "登录成功");
|
|
|
+ if (onLoginSuccess) {
|
|
|
+ onLoginSuccess();
|
|
|
}
|
|
|
+ // 关闭弹窗
|
|
|
+ handleClose();
|
|
|
+ }
|
|
|
+ // 需要验证码时
|
|
|
+ else if (loginStatus === -1) {
|
|
|
+ // 显示验证码输入弹窗
|
|
|
+ setVerifyModalVisible(true);
|
|
|
}
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("轮询登录状态失败:", error);
|
|
|
}
|
|
|
- }, 2000);
|
|
|
+ }, 3000);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 提交验证码
|
|
|
+ const handleVerifySubmit = async () => {
|
|
|
+ if (!verifyCode.trim()) {
|
|
|
+ message.error("请输入验证码");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!qrCodeData) {
|
|
|
+ message.error("二维码数据不存在");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ setVerifyLoading(true);
|
|
|
+ const res = await http.post(qwCheckQRCode, {
|
|
|
+ uuid: qrCodeData.uuid,
|
|
|
+ qrcodeKey: qrCodeData.key,
|
|
|
+ code: verifyCode
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.success) {
|
|
|
+ message.success("验证成功");
|
|
|
+ setVerifyModalVisible(false);
|
|
|
+ // 重置验证码
|
|
|
+ setVerifyCode("");
|
|
|
+ // 重置登录状态,继续轮询
|
|
|
+ setLoginStatus(0);
|
|
|
+ } else {
|
|
|
+ message.error(res.msg || "验证失败");
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ message.error("验证失败");
|
|
|
+ console.error("验证码提交失败:", error);
|
|
|
+ } finally {
|
|
|
+ setVerifyLoading(false);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// 启动倒计时
|
|
@@ -156,13 +196,15 @@ const QrCodeModal: React.FC<QrCodeModalProps> = ({
|
|
|
setCountdown(0);
|
|
|
setLoginStatus(0);
|
|
|
setLoginMessage("");
|
|
|
-
|
|
|
+ setVerifyModalVisible(false);
|
|
|
+ setVerifyCode("");
|
|
|
+
|
|
|
// 清除倒计时定时器
|
|
|
if (timerRef.current) {
|
|
|
clearInterval(timerRef.current);
|
|
|
timerRef.current = null;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 清除轮询定时器
|
|
|
if (pollTimerRef.current) {
|
|
|
clearInterval(pollTimerRef.current);
|
|
@@ -178,7 +220,7 @@ const QrCodeModal: React.FC<QrCodeModalProps> = ({
|
|
|
clearInterval(timerRef.current);
|
|
|
timerRef.current = null;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if (pollTimerRef.current) {
|
|
|
clearInterval(pollTimerRef.current);
|
|
|
pollTimerRef.current = null;
|
|
@@ -191,33 +233,72 @@ const QrCodeModal: React.FC<QrCodeModalProps> = ({
|
|
|
onClose();
|
|
|
};
|
|
|
|
|
|
+ // 处理验证码弹窗关闭
|
|
|
+ const handleVerifyModalClose = () => {
|
|
|
+ setVerifyModalVisible(false);
|
|
|
+ setVerifyCode("");
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
- <Modal
|
|
|
- title={title}
|
|
|
- open={visible}
|
|
|
- onCancel={handleClose}
|
|
|
- footer={null}
|
|
|
- destroyOnClose
|
|
|
- >
|
|
|
- {qrCodeData && (
|
|
|
- <div className="flex flex-col items-center">
|
|
|
- <Image
|
|
|
- src={qrCodeData.qrcode}
|
|
|
- alt="二维码"
|
|
|
- width={200}
|
|
|
- preview={false}
|
|
|
- loading={loading ? 'lazy' : undefined}
|
|
|
+ <>
|
|
|
+ <Modal
|
|
|
+ title={title}
|
|
|
+ open={visible}
|
|
|
+ onCancel={handleClose}
|
|
|
+ footer={null}
|
|
|
+ destroyOnClose
|
|
|
+ >
|
|
|
+ {qrCodeData && (
|
|
|
+ <div className="flex flex-col items-center">
|
|
|
+ <Image
|
|
|
+ src={qrCodeData.qrcode}
|
|
|
+ alt="二维码"
|
|
|
+ width={200}
|
|
|
+ preview={false}
|
|
|
+ loading={loading ? 'lazy' : undefined}
|
|
|
+ />
|
|
|
+ <p className="mt-4 text-center">请使用企业微信扫描二维码</p>
|
|
|
+ <p className="text-center text-gray-500">
|
|
|
+ 二维码有效期 {countdown} 秒
|
|
|
+ {countdown === 0 && (
|
|
|
+ <span className="text-red-500 ml-2">(已过期,请关闭后重试)</span>
|
|
|
+ )}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </Modal>
|
|
|
+
|
|
|
+ {/* 验证码输入弹窗 */}
|
|
|
+ <Modal
|
|
|
+ title="请输入验证码"
|
|
|
+ open={verifyModalVisible}
|
|
|
+ onCancel={handleVerifyModalClose}
|
|
|
+ footer={[
|
|
|
+ <Button key="cancel" onClick={handleVerifyModalClose}>
|
|
|
+ 取消
|
|
|
+ </Button>,
|
|
|
+ <Button
|
|
|
+ key="submit"
|
|
|
+ type="primary"
|
|
|
+ loading={verifyLoading}
|
|
|
+ onClick={handleVerifySubmit}
|
|
|
+ >
|
|
|
+ 确定
|
|
|
+ </Button>,
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <div className="py-4">
|
|
|
+ <p className="mb-4">{loginMessage || "请输入验证码完成登录"}</p>
|
|
|
+ <Input
|
|
|
+ placeholder="请输入验证码"
|
|
|
+ value={verifyCode}
|
|
|
+ onChange={(e) => setVerifyCode(e.target.value)}
|
|
|
+ onPressEnter={handleVerifySubmit}
|
|
|
+ maxLength={6}
|
|
|
/>
|
|
|
- <p className="mt-4 text-center">请使用企业微信扫描二维码</p>
|
|
|
- <p className="text-center text-gray-500">
|
|
|
- 二维码有效期 {countdown} 秒
|
|
|
- {countdown === 0 && (
|
|
|
- <span className="text-red-500 ml-2">(已过期,请关闭后重试)</span>
|
|
|
- )}
|
|
|
- </p>
|
|
|
</div>
|
|
|
- )}
|
|
|
- </Modal>
|
|
|
+ </Modal>
|
|
|
+ </>
|
|
|
);
|
|
|
};
|
|
|
|