'use client' import { useState, useEffect } from 'react' import { signIn } from 'next-auth/react' import { useRouter } from 'next/navigation' import Image from 'next/image' import Link from 'next/link' export default function LoginPage() { const router = useRouter() const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [loading, setLoading] = useState(false) const [error, setError] = useState('') const [showDingtalkModal, setShowDingtalkModal] = useState(false) // 系统设置 const [loginLogoUrl, setLoginLogoUrl] = useState(process.env.NEXT_PUBLIC_DEFAULT_LOGIN_LOGO_URL || '') const [siteName, setSiteName] = useState('由壹点3D素材') // Logo 加载状态 const [logoError, setLogoError] = useState(false) const [logoRetryCount, setLogoRetryCount] = useState(0) // 钉钉配置(从环境变量或配置文件获取) const DINGTALK_CLIENT_ID = process.env.NEXT_PUBLIC_DINGTALK_CLIENT_ID || 'ding1bs1gxwrcfu16x0f' // 加载系统设置 useEffect(() => { const loadSettings = async () => { try { const response = await fetch('/api/system-settings') if (response.ok) { const settings = await response.json() setLoginLogoUrl(settings.loginLogoUrl || process.env.NEXT_PUBLIC_DEFAULT_LOGIN_LOGO_URL || '') setSiteName(settings.siteName || '由壹点3D素材') } } catch (error) { console.error('加载系统设置失败:', error) } } loadSettings() }, []) // 页面加载时识别访问环境 useEffect(() => { const envDomains = (process.env.NEXT_PUBLIC_PUBLIC_DOMAINS || '').split(',').map(s => s.trim()).filter(Boolean) const isPublicDomain = envDomains.length > 0 ? envDomains.includes(window.location.hostname) : false const isIntranet = window.location.hostname.includes('192.168.') if (isPublicDomain) { console.log('🌐 检测到公网访问 (' + window.location.hostname + ')') } else if (isIntranet) { console.log('🏠 检测到内网访问 (' + window.location.hostname + ')') } // 注意:内网检测已改为后端实现(/api/network-status) // 登录成功后会在首页自动调用后端API判断是否需要显示切换提示 }, []) // 处理从内网跳转来的钉钉登录请求 useEffect(() => { const urlParams = new URLSearchParams(window.location.search) const dingtalkRedirect = urlParams.get('dingtalk_redirect') if (dingtalkRedirect === 'true') { console.log('🔄 检测到内网钉钉登录请求,自动触发登录...') // 清理URL参数 window.history.replaceState({}, '', '/login') // 等待页面加载完成后触发钉钉登录 const timer = setTimeout(() => { document.getElementById('dingtalk-login-btn')?.click() }, 500) return () => clearTimeout(timer) } }, []) // 处理钉钉登录成功后的自动登录(内网场景) useEffect(() => { const handleDingtalkAutoLogin = async () => { const urlParams = new URLSearchParams(window.location.search) const dingtalkSuccess = urlParams.get('dingtalk_success') const userEmail = urlParams.get('email') if (dingtalkSuccess === 'true' && userEmail) { setLoading(true) try { // 在内网域名下创建 session const result = await signIn('credentials', { email: decodeURIComponent(userEmail), password: 'dingtalk_auto_login', redirect: false, }) if (result?.error) { setError('登录失败,请重试') } else { // 清除 URL 参数并跳转到首页 window.history.replaceState({}, '', '/login') router.push('/') router.refresh() } } catch (error) { console.error('自动登录失败:', error) setError('登录失败,请重试') } finally { setLoading(false) } } } handleDingtalkAutoLogin() }, [router]) const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setError('') setLoading(true) try { const result = await signIn('credentials', { email, password, redirect: false, }) if (result?.error) { setError(result.error) } else { router.push('/') router.refresh() } } catch (error) { console.error('Login error:', error) setError('登录失败,请稍后再试') } finally { setLoading(false) } } const handleDingtalkLogin = () => { // 强制使用外网域名作为回调地址,支持内网访问 const redirectUrl = process.env.NEXT_PUBLIC_DINGTALK_CALLBACK_URL || `${window.location.origin}/dingtalk-callback` // 在state中携带原始访问地址信息 const isIntranet = window.location.hostname.includes('192.168.') const originUrl = isIntranet ? window.location.origin : '' const stateData = JSON.stringify({ origin: originUrl }) const dingtalkAuthUrl = `https://login.dingtalk.com/oauth2/auth?` + `redirect_uri=${encodeURIComponent(redirectUrl)}` + `&client_id=${DINGTALK_CLIENT_ID}` + `&scope=openid` + `&response_type=code` + `&state=${encodeURIComponent(stateData)}` + `&prompt=consent` // 内网访问:由于混合内容限制,直接跳转到公网域名登录 if (isIntranet) { console.log('🔄 内网环境,跳转到公网域名进行钉钉登录...') const portal = process.env.NEXT_PUBLIC_PORTAL_BASE_URL || window.location.origin window.location.href = `${portal}/login?dingtalk_redirect=true&return_url=${encodeURIComponent(originUrl)}` return } // 公网访问:使用iframe模式 setShowDingtalkModal(true) setTimeout(() => { const iframe = document.getElementById('dingtalkIframe') as HTMLIFrameElement if (iframe) { iframe.src = dingtalkAuthUrl } }, 100) } // 监听来自 iframe 的消息 useEffect(() => { const handleMessage = async (event: MessageEvent) => { if (event.data && event.data.type === 'dingtalk_login_success') { setShowDingtalkModal(false) // 创建 NextAuth session try { const result = await signIn('credentials', { email: event.data.userInfo.email, password: 'dingtalk_auto_login', redirect: false, }) if (result?.error) { setError('登录失败,请重试') } else { // 登录成功,智能跳转 const originUrl = event.data.originUrl if (originUrl && originUrl.includes('192.168.')) { // 从内网发起的登录,跳回内网 window.location.href = originUrl } else if (window.location.hostname.includes('192.168.')) { // 当前在内网,刷新页面 window.location.href = window.location.origin } else { // 外网访问,跳转到首页 router.push('/') router.refresh() } } } catch (error) { console.error('创建session失败:', error) setError('登录失败,请重试') } } else if (event.data && event.data.type === 'dingtalk_need_complete_profile') { setShowDingtalkModal(false) // 跳转到信息完善页面 const userInfoParam = encodeURIComponent(JSON.stringify(event.data.userInfo)) router.push(`/complete-profile?userInfo=${userInfoParam}`) } else if (event.data && event.data.type === 'dingtalk_login_error') { setShowDingtalkModal(false) setError(event.data.message || '钉钉登录失败') } } window.addEventListener('message', handleMessage) return () => window.removeEventListener('message', handleMessage) }, [router]) return (
{/* Logo */}
{loginLogoUrl && !logoError ? ( 0 ? `?retry=${logoRetryCount}` : '')} alt={siteName} width={80} height={80} unoptimized className="rounded-apple shadow-apple" onError={(e) => { const img = e.target as HTMLImageElement setLogoRetryCount((prevCount) => { const newCount = prevCount + 1 if (newCount <= 3) { // 重试加载(最多3次) console.warn(`登录页 Logo 加载失败,正在重试 (${newCount}/3):`, loginLogoUrl) setTimeout(() => { img.src = loginLogoUrl + `?retry=${newCount}` }, 1000 * newCount) // 递增延迟:1s, 2s, 3s return newCount } else { // 重试失败,记录错误并显示占位符 console.error('登录页 Logo 加载失败,已重试3次:', loginLogoUrl) setLogoError(true) img.style.display = 'none' return prevCount } }) }} /> ) : (
{siteName.charAt(0)}
)}

{siteName}

欢迎回来,请登录您的账号

{/* Login Form */}
{error && (
{error}
)}
setEmail(e.target.value)} className="input-apple" placeholder="your@email.com" required />
setPassword(e.target.value)} className="input-apple" placeholder="••••••••" required />
{/* 分隔线 */}
或
{/* 钉钉登录按钮 */}

还没有账号?{' '} 立即注册

{/* 钉钉登录 iframe 弹窗 */} {showDingtalkModal && (
setShowDingtalkModal(false)} >
e.stopPropagation()} >

钉钉扫码登录