add wechat login

This commit is contained in:
hobby
2025-08-22 07:36:19 +08:00
parent 2a4d3f815f
commit 97188321d4
5 changed files with 86 additions and 23 deletions

View File

@@ -7,10 +7,11 @@ import { useIsMobile } from '@/hooks/use-mobile';
import ClickTextCapt from "@/components/goCaptcha/ClickTextCapt.jsx";
interface PhoneLoginProps {
onLogin: (phone: string, code: string) => void;
onLogin?: (phone: string, code: string) => void;
handleLoginSuccess: (token: string) => void;
}
const PhoneLogin: React.FC<PhoneLoginProps> = ({ handleLoginSuccess }) => {
const PhoneLogin: React.FC<PhoneLoginProps> = ({ onLogin, handleLoginSuccess }) => {
const [phone, setPhone] = useState('');
const [code, setCode] = useState('');
const [countdown, setCountdown] = useState(0);
@@ -60,6 +61,12 @@ const PhoneLogin: React.FC<PhoneLoginProps> = ({ handleLoginSuccess }) => {
return;
}
// 如果有 onLogin 回调,先调用它
if (onLogin) {
onLogin(phone, code);
return;
}
setIsLoading(true);
try {
const response = await request(`/api/login`, {

View File

@@ -1,9 +1,13 @@
import React from 'react';
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import PhoneLogin from './comonents/PhoneLogin';
import WechatLogin from './comonents/WechatLogin';
import { useIsMobile } from '@/hooks/use-mobile';
export default function Login() {
const navigate = useNavigate();
const [loginType, setLoginType] = useState('wechat'); // 'phone' | 'wechat'
const isMobile = useIsMobile();
const handleLoginSuccess = (token) => {
localStorage.setItem('token', token);
@@ -17,9 +21,40 @@ export default function Login() {
}
}, []);
// 切换登录方式的按钮
const renderSwitchButton = () => (
<div className="fixed top-4 right-4 z-50">
<button
onClick={() => setLoginType(loginType === 'phone' ? 'wechat' : 'phone')}
className={`flex items-center space-x-2 px-4 py-2 rounded-lg border border-[#ff6600] text-[#ff6600] hover:bg-[#ff6600] hover:text-white transition-colors ${isMobile ? 'text-sm px-3 py-1.5' : 'text-base'}`}
>
{loginType === 'phone' ? (
<>
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path d="M.057 24l1.687-6.163c-1.041-1.804-1.588-3.849-1.587-5.946.003-6.556 5.338-11.891 11.893-11.891 3.181.001 6.167 1.24 8.413 3.488 2.245 2.248 3.481 5.236 3.48 8.414-.003 6.557-5.338 11.892-11.893 11.892-1.99-.001-3.951-.5-5.688-1.448l-6.305 1.654zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-2.462-.96-4.779-2.705-6.526-1.747-1.746-4.066-2.711-6.533-2.713-5.452 0-9.887 4.434-9.889 9.884-.001 2.225.651 3.891 1.746 5.634l-.999 3.648 3.099-.634z"/>
</svg>
<span>微信登录</span>
</>
) : (
<>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
<span>手机登录</span>
</>
)}
</button>
</div>
);
return (
<div className="login-container">
<PhoneLogin handleLoginSuccess={handleLoginSuccess} />
{/* renderSwitchButton() */}
{loginType === 'phone' ? (
<PhoneLogin handleLoginSuccess={handleLoginSuccess} />
) : (
<WechatLogin handleLoginSuccess={handleLoginSuccess} />
)}
</div>
);
}

View File

@@ -1,4 +1,5 @@
// 优先使用运行时配置,降级到构建时配置
// 在开发环境使用代理生产环境使用完整URL
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || '';
export async function request(url: string, options: RequestInit = {}) {
const token = localStorage.getItem('token');

View File

@@ -1,13 +1,33 @@
{
"compilerOptions": {
// ...
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
// ...
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
/* Path mapping */
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@@ -11,14 +11,14 @@ export default defineConfig({
port: 3000,
open: true,
host: true,
// 如果有跨域需求,可以添加代理配置
// proxy: {
// '/api': {
// target: 'your-api-url',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, '')
// }
// }
// 代理配置解决跨域问题
proxy: {
'/api': {
target: 'http://localhost:8082',
changeOrigin: true,
secure: false
}
}
},
resolve: {
alias: {