150 lines
4.1 KiB
JavaScript
150 lines
4.1 KiB
JavaScript
// src/views/Pages/WechatCallback.js
|
||
import React, { useEffect, useState } from "react";
|
||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||
import {
|
||
Box,
|
||
Container,
|
||
VStack,
|
||
Spinner,
|
||
Text,
|
||
Icon,
|
||
useColorModeValue,
|
||
Heading,
|
||
} from "@chakra-ui/react";
|
||
import { FaCheckCircle, FaTimesCircle } from "react-icons/fa";
|
||
import { authService } from "../../services/authService";
|
||
import { useAuth } from "../../contexts/AuthContext";
|
||
import { logger } from "../../utils/logger";
|
||
|
||
/**
|
||
* 微信H5授权回调页面
|
||
* 处理微信授权后的回调,完成登录流程
|
||
*/
|
||
export default function WechatCallback() {
|
||
const navigate = useNavigate();
|
||
const [searchParams] = useSearchParams();
|
||
const { checkSession } = useAuth();
|
||
|
||
const [status, setStatus] = useState("loading"); // loading, success, error
|
||
const [message, setMessage] = useState("正在处理微信授权...");
|
||
|
||
const bgColor = useColorModeValue("gray.50", "gray.900");
|
||
const boxBg = useColorModeValue("white", "gray.800");
|
||
|
||
useEffect(() => {
|
||
const handleCallback = async () => {
|
||
try {
|
||
// 1. 获取URL参数
|
||
const code = searchParams.get("code");
|
||
const state = searchParams.get("state");
|
||
|
||
// 2. 参数验证
|
||
if (!code) {
|
||
throw new Error("授权失败:缺少授权码");
|
||
}
|
||
|
||
// 3. 调用后端处理回调
|
||
const response = await authService.handleWechatH5Callback(code, state);
|
||
|
||
if (!response || !response.success) {
|
||
throw new Error(response?.error || "授权失败,请重试");
|
||
}
|
||
|
||
// 4. 存储用户信息(如果有返回token)
|
||
if (response.token) {
|
||
localStorage.setItem("token", response.token);
|
||
}
|
||
if (response.user) {
|
||
localStorage.setItem("user", JSON.stringify(response.user));
|
||
}
|
||
|
||
// 5. 更新session
|
||
await checkSession();
|
||
|
||
// 6. 显示成功状态
|
||
setStatus("success");
|
||
setMessage("登录成功!正在跳转...");
|
||
|
||
// 7. 延迟跳转到首页
|
||
setTimeout(() => {
|
||
navigate("/home", { replace: true });
|
||
}, 1500);
|
||
} catch (error) {
|
||
logger.error('WechatCallback', 'handleCallback', error, {
|
||
code: searchParams.get("code"),
|
||
state: searchParams.get("state"),
|
||
errorMessage: error.message
|
||
});
|
||
setStatus("error");
|
||
setMessage(error.message || "授权失败,请重试");
|
||
|
||
// 3秒后返回首页
|
||
setTimeout(() => {
|
||
navigate("/home", { replace: true });
|
||
}, 3000);
|
||
}
|
||
};
|
||
|
||
handleCallback();
|
||
}, [searchParams, navigate, checkSession]);
|
||
|
||
return (
|
||
<Box minH="100vh" bg={bgColor} py={12}>
|
||
<Container maxW="container.sm">
|
||
<Box
|
||
bg={boxBg}
|
||
p={8}
|
||
borderRadius="2xl"
|
||
boxShadow="xl"
|
||
textAlign="center"
|
||
>
|
||
<VStack spacing={6}>
|
||
{/* 状态图标 */}
|
||
{status === "loading" && (
|
||
<>
|
||
<Spinner size="xl" color="green.500" thickness="4px" />
|
||
<Heading size="md" color="gray.700">
|
||
处理中
|
||
</Heading>
|
||
</>
|
||
)}
|
||
|
||
{status === "success" && (
|
||
<>
|
||
<Icon
|
||
as={FaCheckCircle}
|
||
w={16}
|
||
h={16}
|
||
color="green.500"
|
||
/>
|
||
<Heading size="md" color="green.600">
|
||
授权成功
|
||
</Heading>
|
||
</>
|
||
)}
|
||
|
||
{status === "error" && (
|
||
<>
|
||
<Icon
|
||
as={FaTimesCircle}
|
||
w={16}
|
||
h={16}
|
||
color="red.500"
|
||
/>
|
||
<Heading size="md" color="red.600">
|
||
授权失败
|
||
</Heading>
|
||
</>
|
||
)}
|
||
|
||
{/* 提示信息 */}
|
||
<Text fontSize="md" color="gray.600">
|
||
{message}
|
||
</Text>
|
||
</VStack>
|
||
</Box>
|
||
</Container>
|
||
</Box>
|
||
);
|
||
}
|