debug: 外链调起诊断面板+全链路日志(临时)
桌面左上角固定调试面板:显示 tauri/osPath/pywebview/pathname 环境判定, 三个按钮分别走 openExternalLink(百度/白名单资讯)与 openInAppWebView; 面板内实时展示最近日志。关键链路埋点 [ext-debug]: openExternalLink 判定 → openInAppWebView → osRouteStore.openApp → osWindowStore.open(含当前窗口列表)→ WebPage mount。
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* ExternalLinkDebug.tsx — 外链调起调试面板(临时诊断用)。
|
||||
*
|
||||
* 固定在桌面左上角,展示当前环境判定与最近日志;三个测试按钮分别走
|
||||
* openExternalLink / openInAppWebView,逐段确认容器为何无法调起。
|
||||
*/
|
||||
import { useCallback, useState } from "react";
|
||||
import {
|
||||
openExternalLink,
|
||||
openInAppWebView,
|
||||
isDesktopTauriRuntime,
|
||||
} from "../../utils/openExternalLink";
|
||||
import { isOsPath } from "../../utils/navigationMode";
|
||||
import { getPyWebViewApi } from "../../utils/pywebview";
|
||||
|
||||
const TEST_URL = "https://www.baidu.com";
|
||||
const TRUST_URL = "https://news.infoepoch.cn";
|
||||
|
||||
export default function ExternalLinkDebug() {
|
||||
const [logs, setLogs] = useState<string[]>([]);
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
const log = useCallback((msg: string) => {
|
||||
console.log(`[ext-debug] ${msg}`);
|
||||
setLogs((prev) => [...prev.slice(-14), msg]);
|
||||
}, []);
|
||||
|
||||
const env = (() => {
|
||||
let pywebview = false;
|
||||
try {
|
||||
pywebview = !!getPyWebViewApi()?.open_external_link;
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
return {
|
||||
tauri: isDesktopTauriRuntime(),
|
||||
osPath: isOsPath(window.location.pathname),
|
||||
pathname: window.location.pathname,
|
||||
pywebview,
|
||||
};
|
||||
})();
|
||||
|
||||
const run = (fn: () => void, label: string) => {
|
||||
log(`▶ ${label} url=${TEST_URL}`);
|
||||
try {
|
||||
fn();
|
||||
log(" 调用已同步返回(异步结果见后续日志)");
|
||||
} catch (e) {
|
||||
log(` ✗ 同步抛错: ${String(e)}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: 44,
|
||||
left: 12,
|
||||
zIndex: 99999,
|
||||
width: 300,
|
||||
background: "rgba(20,20,24,0.92)",
|
||||
color: "#e8e8ea",
|
||||
borderRadius: 10,
|
||||
padding: 8,
|
||||
fontSize: 11,
|
||||
fontFamily: "monospace",
|
||||
lineHeight: 1.5,
|
||||
boxShadow: "0 6px 24px rgba(0,0,0,0.35)",
|
||||
userSelect: "text",
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", gap: 6, alignItems: "center" }}>
|
||||
<b style={{ flex: 1 }}>外链调试</b>
|
||||
<button
|
||||
onClick={() => setCollapsed((c) => !c)}
|
||||
style={{ background: "#333", color: "#eee", border: "none", borderRadius: 4, cursor: "pointer" }}
|
||||
>
|
||||
{collapsed ? "展开" : "收起"}
|
||||
</button>
|
||||
</div>
|
||||
{!collapsed && (
|
||||
<>
|
||||
<div style={{ margin: "6px 0", padding: 6, background: "#00000055", borderRadius: 6 }}>
|
||||
<div>tauri={String(env.tauri)} osPath={String(env.osPath)} pywebview={String(env.pywebview)}</div>
|
||||
<div style={{ wordBreak: "break-all" }}>path={env.pathname}</div>
|
||||
</div>
|
||||
<div style={{ display: "flex", gap: 6, marginBottom: 6, flexWrap: "wrap" }}>
|
||||
<button
|
||||
onClick={() => run(() => openExternalLink(TEST_URL), "openExternalLink(百度)")}
|
||||
style={{ background: "#2f6fed", color: "#fff", border: "none", borderRadius: 4, padding: "3px 8px", cursor: "pointer" }}
|
||||
>
|
||||
外链·百度
|
||||
</button>
|
||||
<button
|
||||
onClick={() => run(() => openInAppWebView(TEST_URL), "openInAppWebView(百度)")}
|
||||
style={{ background: "#2f6fed", color: "#fff", border: "none", borderRadius: 4, padding: "3px 8px", cursor: "pointer" }}
|
||||
>
|
||||
直开容器·百度
|
||||
</button>
|
||||
<button
|
||||
onClick={() => run(() => openExternalLink(TRUST_URL), "openExternalLink(白名单)")}
|
||||
style={{ background: "#3a9d5d", color: "#fff", border: "none", borderRadius: 4, padding: "3px 8px", cursor: "pointer" }}
|
||||
>
|
||||
白名单·资讯
|
||||
</button>
|
||||
</div>
|
||||
<div style={{ maxHeight: 260, overflow: "auto", borderTop: "1px solid #444", paddingTop: 4 }}>
|
||||
{logs.length === 0 ? (
|
||||
<div style={{ color: "#888" }}>(暂无日志,点击上方按钮)</div>
|
||||
) : (
|
||||
logs.map((l, i) => (
|
||||
<div key={i} style={{ whiteSpace: "pre-wrap", wordBreak: "break-all" }}>
|
||||
{l}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import { isAgentAvailableInChat } from "../utils/agentVisibility";
|
||||
import { purgeAppState, removePluginAppState } from "./osCleanup";
|
||||
import WindowFrame from "./WindowFrame";
|
||||
import WindowRouter from "./WindowRouter";
|
||||
import ExternalLinkDebug from "../components/ExternalLinkDebug";
|
||||
import { baseFromRoutePath } from "./osRouteMap";
|
||||
import MenuBar from "./MenuBar";
|
||||
import Dock from "./Dock";
|
||||
@@ -477,7 +478,7 @@ export default function DesktopOS() {
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className={styles.loading}>
|
||||
<Spin tip={t("common.loading")} />
|
||||
<Spin />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
@@ -544,6 +545,9 @@ export default function DesktopOS() {
|
||||
{wpOpen && <WallpaperPicker onClose={() => setWpOpen(false)} />}
|
||||
|
||||
{booting && <BootScreen onDone={handleBootDone} />}
|
||||
|
||||
{/* 外链调起调试面板(诊断用,临时) */}
|
||||
<ExternalLinkDebug />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ export const useOsRoute = create<OsRouteStore>((set) => ({
|
||||
targets: {},
|
||||
|
||||
openApp: (routeId, path) => {
|
||||
console.log("[ext-debug] osRouteStore.openApp", JSON.stringify({ routeId, path }));
|
||||
if (path !== undefined) {
|
||||
set((s) => ({
|
||||
targets: {
|
||||
|
||||
@@ -187,6 +187,7 @@ export const useOsWindows = create<OsStore>()(
|
||||
|
||||
open: (id, size) => {
|
||||
const state = get();
|
||||
console.log("[ext-debug] osWindowStore.open", JSON.stringify({ id, exists: !!state.windows[id], openIds: Object.keys(state.windows) }));
|
||||
if (state.windows[id]) {
|
||||
// Already open — restore if minimized, then focus.
|
||||
set((s) => ({
|
||||
|
||||
@@ -34,7 +34,11 @@ export default function WebPage() {
|
||||
const location = useLocation();
|
||||
const close = useOsWindows((s) => s.close);
|
||||
const navigate = useNavigate();
|
||||
const [targetUrl, setTargetUrl] = useState(() => parseWebUrl(location.search));
|
||||
const [targetUrl, setTargetUrl] = useState(() => {
|
||||
const u = parseWebUrl(location.search);
|
||||
console.log("[ext-debug] WebPage mount", JSON.stringify({ search: location.search, url: u }));
|
||||
return u;
|
||||
});
|
||||
// 白名单标识:unknown(判定中)/ trusted / third-party
|
||||
const [trust, setTrust] = useState<"unknown" | "trusted" | "third-party">("unknown");
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
@@ -127,6 +127,7 @@ export function openExternalLink(
|
||||
|
||||
const fullUrl = resolveSupportedExternalUrl(url);
|
||||
if (!fullUrl) {
|
||||
console.warn("[ext-debug] openExternalLink: 非支持协议,已忽略", url);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,14 +135,19 @@ export function openExternalLink(
|
||||
// forceSystem=true 时(容器内「系统浏览器打开」)跳过接管。
|
||||
try {
|
||||
const proto = new URL(fullUrl).protocol;
|
||||
const isDesktopShell =
|
||||
isDesktopTauriRuntime() || isOsPath(window.location.pathname);
|
||||
const tauri = isDesktopTauriRuntime();
|
||||
const osPath = isOsPath(window.location.pathname);
|
||||
const isDesktopShell = tauri || osPath;
|
||||
console.log(
|
||||
"[ext-debug] openExternalLink 判定",
|
||||
JSON.stringify({ url, fullUrl, proto, tauri, osPath, isDesktopShell, forceSystem }),
|
||||
);
|
||||
if (!forceSystem && HTTP_PROTOCOLS.has(proto) && isDesktopShell) {
|
||||
openInAppWebView(fullUrl);
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
/* fall through */
|
||||
} catch (e) {
|
||||
console.warn("[ext-debug] openExternalLink 判定异常", e);
|
||||
}
|
||||
|
||||
const runtime = detectExternalLinkRuntime(fullUrl);
|
||||
@@ -168,6 +174,7 @@ export function openExternalLink(
|
||||
export function openInAppWebView(fullUrl: string): void {
|
||||
try {
|
||||
const path = `/webpage?url=${encodeURIComponent(fullUrl)}`;
|
||||
console.log("[ext-debug] openInAppWebView → openApp", JSON.stringify({ routeId: "core.web-view", path }));
|
||||
useOsRoute.getState().openApp("core.web-view", path);
|
||||
} catch (e) {
|
||||
console.warn("[external-link] in-app web view open failed", e);
|
||||
|
||||
Reference in New Issue
Block a user