mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-21 13:59:03 +08:00
194 lines
5.0 KiB
TypeScript
194 lines
5.0 KiB
TypeScript
import "./assets/main.css"
|
|
import "./i18n"
|
|
|
|
import { StrictMode } from "react"
|
|
import { createRoot } from "react-dom/client"
|
|
import App from "./App"
|
|
import { ClientContext } from "./ClientContext"
|
|
import { StudentService } from "./services/StudentService"
|
|
import { ServiceProvider } from "./contexts/ServiceContext"
|
|
import { api } from "./preload/types"
|
|
|
|
if (!(window as any).api) {
|
|
;(window as any).api = api
|
|
}
|
|
|
|
const ctx = new ClientContext()
|
|
new StudentService(ctx)
|
|
|
|
const safeWriteLog = (payload: {
|
|
level: "debug" | "info" | "warn" | "error"
|
|
message: string
|
|
meta?: any
|
|
}) => {
|
|
try {
|
|
const api = (window as any).api
|
|
if (!api?.writeLog) return
|
|
Promise.resolve(api.writeLog(payload)).catch(() => void 0)
|
|
} catch {
|
|
return
|
|
}
|
|
}
|
|
|
|
const patchConsole = () => {
|
|
const c = window.console as any
|
|
const original = {
|
|
log: typeof c.log === "function" ? c.log.bind(c) : undefined,
|
|
info: typeof c.info === "function" ? c.info.bind(c) : undefined,
|
|
warn: typeof c.warn === "function" ? c.warn.bind(c) : undefined,
|
|
debug: typeof c.debug === "function" ? c.debug.bind(c) : undefined,
|
|
error: typeof c.error === "function" ? c.error.bind(c) : undefined,
|
|
trace: typeof c.trace === "function" ? c.trace.bind(c) : undefined,
|
|
table: typeof c.table === "function" ? c.table.bind(c) : undefined,
|
|
}
|
|
const set = (name: string, fn: (...args: any[]) => void) => {
|
|
try {
|
|
c[name] = fn
|
|
} catch {
|
|
void 0
|
|
}
|
|
}
|
|
|
|
set("log", (...args: any[]) => {
|
|
safeWriteLog({ level: "info", message: String(args[0] ?? ""), meta: args.slice(1) })
|
|
original.log?.(...args)
|
|
})
|
|
set("info", (...args: any[]) => {
|
|
safeWriteLog({ level: "info", message: String(args[0] ?? ""), meta: args.slice(1) })
|
|
original.info?.(...args)
|
|
})
|
|
set("warn", (...args: any[]) => {
|
|
safeWriteLog({ level: "warn", message: String(args[0] ?? ""), meta: args.slice(1) })
|
|
original.warn?.(...args)
|
|
})
|
|
set("debug", (...args: any[]) => {
|
|
safeWriteLog({ level: "debug", message: String(args[0] ?? ""), meta: args.slice(1) })
|
|
original.debug?.(...args)
|
|
})
|
|
set("error", (...args: any[]) => {
|
|
const first = args[0]
|
|
if (first instanceof Error) {
|
|
safeWriteLog({
|
|
level: "error",
|
|
message: first.message,
|
|
meta: { stack: first.stack, args: args.slice(1) },
|
|
})
|
|
original.error?.(...args)
|
|
return
|
|
}
|
|
safeWriteLog({ level: "error", message: String(first ?? ""), meta: args.slice(1) })
|
|
original.error?.(...args)
|
|
})
|
|
set("trace", (...args: any[]) => {
|
|
safeWriteLog({
|
|
level: "debug",
|
|
message: "console.trace",
|
|
meta: { args, stack: new Error("console.trace").stack },
|
|
})
|
|
original.trace?.(...args)
|
|
})
|
|
set("table", (...args: any[]) => {
|
|
safeWriteLog({ level: "info", message: "console.table", meta: args })
|
|
original.table?.(...args)
|
|
})
|
|
}
|
|
patchConsole()
|
|
|
|
const disableTouchZoom = () => {
|
|
let lastTouchEnd = 0
|
|
|
|
// iOS Safari/WebView 手势事件,直接阻止页面缩放
|
|
for (const type of ["gesturestart", "gesturechange", "gestureend"]) {
|
|
document.addEventListener(
|
|
type,
|
|
(event) => {
|
|
event.preventDefault()
|
|
},
|
|
{ passive: false }
|
|
)
|
|
}
|
|
|
|
// 双指触摸移动时阻止缩放
|
|
document.addEventListener(
|
|
"touchmove",
|
|
(event) => {
|
|
if (event.touches.length > 1) {
|
|
event.preventDefault()
|
|
}
|
|
},
|
|
{ passive: false }
|
|
)
|
|
|
|
// 连续快速双击时阻止浏览器放大
|
|
document.addEventListener(
|
|
"touchend",
|
|
(event) => {
|
|
const now = Date.now()
|
|
if (now - lastTouchEnd <= 300) {
|
|
event.preventDefault()
|
|
}
|
|
lastTouchEnd = now
|
|
},
|
|
{ passive: false }
|
|
)
|
|
|
|
// 部分环境下双击会触发 dblclick,补充阻止
|
|
document.addEventListener(
|
|
"dblclick",
|
|
(event) => {
|
|
event.preventDefault()
|
|
},
|
|
{ passive: false }
|
|
)
|
|
}
|
|
disableTouchZoom()
|
|
|
|
const platform = navigator.userAgent.toLowerCase()
|
|
const isIos = /iphone|ipad|ipod/.test(platform)
|
|
const isAndroid = platform.includes("android")
|
|
const isMacDesktop = platform.includes("mac") && !isIos
|
|
|
|
if (isMacDesktop) {
|
|
document.documentElement.classList.add("platform-macos")
|
|
}
|
|
|
|
if (isIos) {
|
|
document.documentElement.classList.add("platform-ios")
|
|
}
|
|
|
|
if (isAndroid) {
|
|
document.documentElement.classList.add("platform-android")
|
|
}
|
|
|
|
window.addEventListener("error", (e: any) => {
|
|
const error = e?.error
|
|
safeWriteLog({
|
|
level: "error",
|
|
message: "renderer:error",
|
|
meta: {
|
|
message: error?.message || e?.message,
|
|
stack: error?.stack,
|
|
filename: e?.filename,
|
|
lineno: e?.lineno,
|
|
colno: e?.colno,
|
|
},
|
|
})
|
|
})
|
|
|
|
window.addEventListener("unhandledrejection", (e: any) => {
|
|
const reason = e?.reason
|
|
safeWriteLog({
|
|
level: "error",
|
|
message: "renderer:unhandledrejection",
|
|
meta: reason instanceof Error ? { message: reason.message, stack: reason.stack } : { reason },
|
|
})
|
|
})
|
|
|
|
createRoot(document.getElementById("root")!).render(
|
|
<StrictMode>
|
|
<ServiceProvider value={ctx}>
|
|
<App />
|
|
</ServiceProvider>
|
|
</StrictMode>
|
|
)
|