feat: initial commit - massive-cloud point cloud processing system

This commit is contained in:
2026-05-27 09:51:42 +00:00
commit 16811100d1
391 changed files with 78338 additions and 0 deletions

99
client/src/main.tsx Normal file
View File

@@ -0,0 +1,99 @@
import { trpc } from "@/lib/trpc";
import { UNAUTHED_ERR_MSG } from '@shared/const';
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { httpBatchLink, httpLink, splitLink, TRPCClientError } from "@trpc/client";
import { createRoot } from "react-dom/client";
import superjson from "superjson";
import App from "./App";
import { getLoginUrl } from "./const";
import "./index.css";
// 禁用 HMR 失败时的自动页面刷新,保留热更新功能
if (import.meta.hot) {
// 阻止 HMR 失败时的完整页面刷新
import.meta.hot.on('vite:beforeFullReload', (payload) => {
console.log('[HMR] Preventing full reload, change detected:', payload);
// 返回 false 阻止刷新(但这个钩子实际上不能阻止,只是通知)
});
// 当 HMR 更新失败时,不刷新页面,只在控制台显示警告
import.meta.hot.on('vite:error', (err) => {
console.warn('[HMR] Update failed, manual refresh may be needed:', err);
});
// 接受所有模块更新,防止因某些模块不支持 HMR 而触发刷新
import.meta.hot.accept(() => {
console.log('[HMR] Module updated');
});
}
const queryClient = new QueryClient();
const redirectToLoginIfUnauthorized = (error: unknown) => {
if (!(error instanceof TRPCClientError)) return;
if (typeof window === "undefined") return;
const isUnauthorized = error.message === UNAUTHED_ERR_MSG;
if (!isUnauthorized) return;
window.location.href = getLoginUrl();
};
queryClient.getQueryCache().subscribe(event => {
if (event.type === "updated" && event.action.type === "error") {
const error = event.query.state.error;
redirectToLoginIfUnauthorized(error);
console.error("[API Query Error]", error);
}
});
queryClient.getMutationCache().subscribe(event => {
if (event.type === "updated" && event.action.type === "error") {
const error = event.mutation.state.error;
redirectToLoginIfUnauthorized(error);
console.error("[API Mutation Error]", error);
}
});
const trpcLinkOptions = {
url: "/api/trpc",
transformer: superjson,
fetch(input: RequestInfo | URL, init?: RequestInit) {
// 给每个请求加时间戳,防止 NPS / 反向代理缓存 GET 响应
let url: string;
if (input instanceof URL) {
input.searchParams.set('_t', Date.now().toString());
url = input.toString();
} else if (typeof input === 'string') {
const sep = input.includes('?') ? '&' : '?';
url = `${input}${sep}_t=${Date.now()}`;
} else {
url = input as string;
}
return globalThis.fetch(url, {
...(init ?? {}),
credentials: "include",
});
},
} as const;
const trpcClient = trpc.createClient({
links: [
splitLink({
condition(op) {
return op.type === "mutation";
},
true: httpLink(trpcLinkOptions),
false: httpBatchLink(trpcLinkOptions),
}),
],
});
createRoot(document.getElementById("root")!).render(
<trpc.Provider client={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</trpc.Provider>
);