fix: v3.0 bug修复——分享权限区分、session_not_found友好提示、图片识别配置

This commit is contained in:
root 2026-02-23 17:51:03 +00:00
parent 3340b6ace3
commit dfce4fc88f

View File

@ -1,6 +1,7 @@
'use client'; 'use client';
import { useEffect, useMemo, useRef, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
import { useRouter } from 'next/navigation';
import Starfield from '../../components/Starfield'; import Starfield from '../../components/Starfield';
const ZODIAC_SYMBOL = { const ZODIAC_SYMBOL = {
@ -81,6 +82,11 @@ export default function ReportPreviewPage() {
const [error, setError] = useState(''); const [error, setError] = useState('');
const headerRef = useRef(null); const headerRef = useRef(null);
const [headerVisible, setHeaderVisible] = useState(false); const [headerVisible, setHeaderVisible] = useState(false);
const [showShare, setShowShare] = useState(false);
const [copied, setCopied] = useState(false);
const [showRestart, setShowRestart] = useState(false);
const [isOwner, setIsOwner] = useState(false);
const router = useRouter();
useEffect(() => { useEffect(() => {
if (typeof window === 'undefined') return; if (typeof window === 'undefined') return;
@ -112,7 +118,12 @@ export default function ReportPreviewPage() {
setData(d.report); setData(d.report);
return; return;
} }
if (d?.status === 'error') throw new Error(d?.error || '生成失败'); if (d?.status === 'error') {
if (d?.error === 'session_not_found') {
throw new Error('SESSION_NOT_FOUND');
}
throw new Error(d?.error || '生成失败');
}
// generating not_started 2 // generating not_started 2
if (attempt < 29) { if (attempt < 29) {
await new Promise(resolve => setTimeout(resolve, 2000)); await new Promise(resolve => setTimeout(resolve, 2000));
@ -123,7 +134,13 @@ export default function ReportPreviewPage() {
finally { setLoading(false); } finally { setLoading(false); }
}; };
useEffect(() => { load(); }, [sid]); useEffect(() => {
if (sid) {
const localSid = localStorage.getItem('lingjing_sid') || '';
setIsOwner(localSid === sid);
load();
}
}, [sid]);
return ( return (
<main className="relative min-h-screen overflow-hidden bg-[#05030f] text-white"> <main className="relative min-h-screen overflow-hidden bg-[#05030f] text-white">
@ -133,7 +150,7 @@ export default function ReportPreviewPage() {
<header ref={headerRef} className="mb-8 text-center" <header ref={headerRef} className="mb-8 text-center"
style={{ opacity: headerVisible ? 1 : 0, transform: headerVisible ? 'translateY(0)' : 'translateY(-20px)', transition: 'opacity 0.8s ease, transform 0.8s ease' }}> style={{ opacity: headerVisible ? 1 : 0, transform: headerVisible ? 'translateY(0)' : 'translateY(-20px)', transition: 'opacity 0.8s ease, transform 0.8s ease' }}>
<p className="text-xs tracking-[0.3em] text-white/35">LINGJING REPORT</p> <p className="text-xs tracking-[0.3em] text-white/35">LINGJING REPORT</p>
<h1 className="mt-2 text-3xl font-light tracking-widest">你的灵镜报告</h1> <h1 className="mt-2 text-3xl font-light tracking-widest">{isOwner ? '你的灵镜报告' : 'ta的灵镜报告'}</h1>
</header> </header>
{loading ? ( {loading ? (
@ -145,8 +162,18 @@ export default function ReportPreviewPage() {
) : null} ) : null}
{error ? ( {error ? (
<div className="mx-auto max-w-xl rounded-2xl border border-white/10 bg-white/5 p-6 text-center"> <div className="mx-auto max-w-xl rounded-2xl border border-white/10 bg-white/5 p-6 text-center">
<p className="text-red-300">{error}</p> {error === 'SESSION_NOT_FOUND' ? (
<button className="mt-4 rounded-xl border border-white/20 px-4 py-2 text-sm" onClick={load}>重试</button> <>
<p className="text-white/70 mb-2">找不到你的报告记录</p>
<p className="text-xs text-white/40 mb-4">可能是之前的对话已过期</p>
<button className="rounded-xl border border-white/20 bg-white/10 px-5 py-2.5 text-sm text-white" onClick={() => { localStorage.removeItem('lingjing_sid'); router.replace('/chat'); }}>重新开始</button>
</>
) : (
<>
<p className="text-red-300">{error}</p>
<button className="mt-4 rounded-xl border border-white/20 px-4 py-2 text-sm" onClick={load}>重试</button>
</>
)}
</div> </div>
) : null} ) : null}
@ -311,7 +338,97 @@ export default function ReportPreviewPage() {
</div> </div>
) : null} ) : null}
{/* 底部操作区(仅本人可见) */}
{!loading && !error && data && isOwner ? (
<div className="mt-10 flex flex-col items-center gap-4 pb-12">
<button
onClick={() => setShowShare(true)}
className="w-full max-w-xs rounded-full border border-white/30 bg-white/10 py-3 text-sm tracking-widest text-white/90 backdrop-blur-sm transition hover:bg-white/20"
>
分享给朋友
</button>
<button
onClick={() => setShowRestart(true)}
className="text-xs text-white/30 underline underline-offset-4 hover:text-white/50 transition"
>
重新开始
</button>
</div>
) : null}
</div> </div>
{/* 分享弹窗 */}
{showShare ? (
<div className="fixed inset-0 z-50 flex items-end justify-center bg-black/60 backdrop-blur-sm" onClick={() => setShowShare(false)}>
<div className="w-full max-w-lg rounded-t-3xl bg-[#0e0b1f] border-t border-white/10 p-6 pb-10" onClick={e => e.stopPropagation()}>
<h3 className="text-center text-base font-semibold text-white mb-1">分享给朋友</h3>
<p className="text-center text-xs text-white/40 mb-5">朋友可以直接看到你的完整报告</p>
<div className="flex items-center gap-2 rounded-xl border border-white/15 bg-white/5 px-4 py-3 mb-4">
<p className="flex-1 truncate text-xs text-white/60 font-mono">
{typeof window !== 'undefined' ? window.location.href : ''}
</p>
<button
onClick={() => {
if (typeof window !== 'undefined') {
navigator.clipboard.writeText(window.location.href).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
});
}
}}
className="shrink-0 rounded-lg bg-white/15 px-3 py-1.5 text-xs text-white hover:bg-white/25 transition"
>
{copied ? '已复制 ✓' : '复制链接'}
</button>
</div>
<p className="text-center text-xs text-white/30">朋友看完可以在页面底部做自己的报告</p>
<button onClick={() => setShowShare(false)} className="mt-5 w-full rounded-full border border-white/15 py-3 text-sm text-white/50 hover:text-white/80 transition">关闭</button>
</div>
</div>
) : null}
{/* 重做确认弹窗 */}
{showRestart ? (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm" onClick={() => setShowRestart(false)}>
<div className="w-full max-w-sm mx-4 rounded-2xl bg-[#0e0b1f] border border-white/10 p-6" onClick={e => e.stopPropagation()}>
<h3 className="text-base font-semibold text-white mb-2">重新开始</h3>
<p className="text-sm text-white/50 leading-6 mb-6">重新开始会生成全新报告当前报告不会保留确定吗</p>
<div className="flex gap-3">
<button
onClick={() => setShowRestart(false)}
className="flex-1 rounded-full border border-white/20 py-2.5 text-sm text-white/60 hover:text-white/90 transition"
>
取消
</button>
<button
onClick={() => {
localStorage.removeItem('lingjing_sid');
router.replace('/chat');
}}
className="flex-1 rounded-full bg-white/15 py-2.5 text-sm text-white hover:bg-white/25 transition"
>
确定重新开始
</button>
</div>
</div>
</div>
) : null}
{/* 分享页底部引导(仅非本人查看时显示) */}
{!isOwner ? (
<div className="relative z-10 border-t border-white/5 bg-[#05030f] px-4 py-8 text-center">
<p className="text-sm text-white/40 mb-4">看完 ta 的报告来做你自己的</p>
<button
onClick={() => { localStorage.removeItem('lingjing_sid'); router.push('/chat'); }}
className="rounded-full border border-white/20 px-8 py-3 text-sm text-white/80 hover:bg-white/10 transition"
>
开始我的灵镜报告
</button>
</div>
) : null}
</main> </main>
); );
} }