feat:授权回调修改

This commit is contained in:
非凡主儿 2025-10-20 21:47:33 +08:00
parent d3db6388e1
commit 8e1901f72c
4 changed files with 79 additions and 13 deletions

View File

@ -7,10 +7,37 @@ export default function TwitterAuthCallbackPage() {
const router = useRouter(); const router = useRouter();
useEffect(() => { useEffect(() => {
// 此页面主要是为了 Next.js 路由捕获回调 URL。 // 解析回调参数
// 在 ShareModal 检测到参数后会打开 TwitterCallbackModal。 const searchParams = new URLSearchParams(window.location.search);
// 重定向到主页面或相关仪表板页面。 const state = searchParams.get('state');
// 参数将由 ShareModal 接收处理。 const code = searchParams.get('code');
// 将回调参数写入 localStorage供原窗口读取
if (state && code) {
try {
const payload = {
state,
code,
timestamp: Date.now(),
};
localStorage.setItem('twitterAuthCallbackPayload', JSON.stringify(payload));
// 通过变化一个随机标记键,确保触发其它窗口的 storage 事件
localStorage.setItem('twitterAuthCallbackFlag', Math.random().toString(36).slice(2));
} catch {
// 忽略本地存储异常
}
// 通过 postMessage 通知打开者(如果存在且同源策略允许)
try {
if (window.opener) {
window.opener.postMessage({ type: 'TWITTER_AUTH_CALLBACK', state, code }, window.location.origin);
}
} catch {
}
}
// 跳回应用页面(原窗口会通过 storage 事件弹出处理弹框)
router.push('/movies?twitterCallback=true'); router.push('/movies?twitterCallback=true');
}, [router]); }, [router]);

View File

@ -103,16 +103,53 @@ export default function ShareModal({ visible, onClose, project }: ShareModalProp
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
const state = urlParams.get('state'); const state = urlParams.get('state');
const code = urlParams.get('code'); const code = urlParams.get('code');
// 检查是否是 Twitter 授权回调 // 当前就在回调路径(同窗口授权)
if (state && code && window.location.pathname.includes('/api/video-share/x/auth/callback')) { if (state && code && window.location.pathname.includes('/api/video-share/x/auth/callback')) {
setTwitterCallbackParams({ state, code }); setTwitterCallbackParams({ state, code });
setTwitterCallbackVisible(true); setTwitterCallbackVisible(true);
// 清理 URL 参数
const newUrl = window.location.pathname; const newUrl = window.location.pathname;
window.history.replaceState({}, document.title, newUrl); window.history.replaceState({}, document.title, newUrl);
return;
} }
// 新窗口授权,回到非回调路径,比如 /movies?twitterCallback=true
const hasFlag = urlParams.get('twitterCallback') === 'true';
const cached = localStorage.getItem('twitterAuthCallbackPayload');
if (hasFlag && cached) {
try {
const parsed = JSON.parse(cached);
if (parsed?.state && parsed?.code) {
setTwitterCallbackParams({ state: parsed.state, code: parsed.code });
setTwitterCallbackVisible(true);
}
} catch {
}
// 清理 URL 中的 twitterCallback 标记
const cleanUrl = window.location.pathname;
window.history.replaceState({}, document.title, cleanUrl);
}
// 监听 storage 事件(跨窗口通知)
const onStorage = (e: StorageEvent) => {
if (e.key === 'twitterAuthCallbackFlag') {
const cachedPayload = localStorage.getItem('twitterAuthCallbackPayload');
if (cachedPayload) {
try {
const parsed = JSON.parse(cachedPayload);
if (parsed?.state && parsed?.code) {
setTwitterCallbackParams({ state: parsed.state, code: parsed.code });
setTwitterCallbackVisible(true);
}
} catch {
}
}
}
};
window.addEventListener('storage', onStorage);
return () => window.removeEventListener('storage', onStorage);
} }
}, []); }, []);
@ -306,6 +343,11 @@ export default function ShareModal({ visible, onClose, project }: ShareModalProp
onClose={() => { onClose={() => {
setTwitterCallbackVisible(false); setTwitterCallbackVisible(false);
setTwitterCallbackParams(null); setTwitterCallbackParams(null);
// 关闭时清理临时缓存
try {
localStorage.removeItem('twitterAuthCallbackPayload');
localStorage.removeItem('twitterAuthCallbackFlag');
} catch {}
}} }}
project={project} project={project}
urlParams={twitterCallbackParams} urlParams={twitterCallbackParams}

View File

@ -2,7 +2,7 @@
import { useState, useEffect, useRef, useCallback } from 'react'; import { useState, useEffect, useRef, useCallback } from 'react';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import { Loader2, Download, Share } from 'lucide-react'; import { Loader2, Download, Send } from 'lucide-react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import './style/create-to-video2.css'; import './style/create-to-video2.css';
@ -382,7 +382,7 @@ export default function CreateToVideo2() {
className="w-[2.5rem] h-[2.5rem] rounded-full items-center justify-center p-0 hidden group-hover:flex transition-all duration-300 hover:bg-white/15" className="w-[2.5rem] h-[2.5rem] rounded-full items-center justify-center p-0 hidden group-hover:flex transition-all duration-300 hover:bg-white/15"
onClick={(e) => handleShareClick(e, project)} onClick={(e) => handleShareClick(e, project)}
> >
<Share className="w-4 h-4 text-white" /> <Send className="w-4 h-4 text-white" />
</Button> </Button>
</Tooltip> </Tooltip>
{/* 下载按钮 */} {/* 下载按钮 */}

View File

@ -155,9 +155,6 @@ export const validateEnvConfig = (): { isValid: boolean; errors: string[] } => {
errors.push('NEXT_PUBLIC_JAVA_URL is required'); errors.push('NEXT_PUBLIC_JAVA_URL is required');
} }
if (!baseUrl) {
errors.push('NEXT_PUBLIC_SHARE_API_URL is required');
}
if (!googleClientId) { if (!googleClientId) {
errors.push('NEXT_PUBLIC_GOOGLE_CLIENT_ID is required'); errors.push('NEXT_PUBLIC_GOOGLE_CLIENT_ID is required');