- 题目页:安卓按返回键收键盘时编辑器不失焦,符号键一直贴底、「运行例子 / 提交」不回来。 改成看键盘真弹着没有(可视视口变矮),不只看焦点 - 比赛排名:结束后的领奖台三块共 646px,手机上第一名被切掉、第三名看不见;改成平分一行 - iPhone:点 14/15px 的输入框和代码编辑器,Safari 会整页放大且不缩回;只给 iOS 加 maximum-scale=1 - 登录:手机上选完班不再自动聚焦搜索框(键盘弹出来盖住半张名单) - 题单:窄屏上题目拆成两张没标题的卡片,像分了两组;放不下两栏时合成一张 - 「中等」在题目页是蓝色、在题目列表是橙色,统一成橙色 - 零碎:自学四列表格在 360 宽上收窄格子;统计「错得最多的题」表头不再挤成竖排; 「第 N 名」「14 道」不再把最后一个字甩到下一行 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
98 lines
2.8 KiB
TypeScript
98 lines
2.8 KiB
TypeScript
import { addAPIProvider } from "@iconify/vue"
|
|
import { createPinia } from "pinia"
|
|
import { createRouter, createWebHistory } from "vue-router"
|
|
|
|
import { STORAGE_KEY } from "utils/constants"
|
|
import storage from "utils/storage"
|
|
|
|
import App from "./App.vue"
|
|
import { admins, ojs } from "./routes"
|
|
|
|
/**
|
|
* iPhone 上点进字号小于 16px 的输入框(Naive 的输入框是 14px、代码编辑器 15px),
|
|
* Safari 会自动把整页放大,而且退出输入也不缩回去,得学生自己双指缩。
|
|
* maximum-scale=1 能关掉这个自动放大;iOS 10 起照样允许双指缩放,所以只给 iOS 加 ——
|
|
* 安卓上这么写会真的禁掉双指放大,看题面图片、代码就没法放大了。
|
|
*/
|
|
const isIOS =
|
|
/iPhone|iPad|iPod/.test(navigator.userAgent) ||
|
|
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1)
|
|
if (isIOS) {
|
|
const viewport = document.querySelector('meta[name="viewport"]')
|
|
viewport?.setAttribute("content", "width=device-width, initial-scale=1.0, maximum-scale=1")
|
|
}
|
|
|
|
const router = createRouter({
|
|
history: createWebHistory(),
|
|
routes: [ojs, admins],
|
|
})
|
|
|
|
const pinia = createPinia()
|
|
|
|
// 创建 app 并安装插件
|
|
const app = createApp(App)
|
|
app.use(pinia)
|
|
app.use(router)
|
|
|
|
// 现在可以安全地使用 Store
|
|
import { useAuthModalStore } from "./shared/store/authModal"
|
|
import { useUserStore } from "./shared/store/user"
|
|
|
|
const authStore = useAuthModalStore()
|
|
|
|
// vue-router 5.4 起 next() 回调已弃用,改成返回值:返回 "/" 就是跳回首页,什么都不返回就是放行
|
|
router.beforeEach(async (to) => {
|
|
// 检查是否需要认证
|
|
if (to.matched.some((record) => record.meta.requiresAuth)) {
|
|
if (!storage.get(STORAGE_KEY.AUTHED)) {
|
|
authStore.openLoginModal()
|
|
return "/"
|
|
}
|
|
}
|
|
|
|
// 检查权限
|
|
if (
|
|
to.matched.some(
|
|
(record) =>
|
|
record.meta.requiresSuperAdmin ||
|
|
record.meta.requiresTeacherAdmin ||
|
|
record.meta.requiresProblemPermission,
|
|
)
|
|
) {
|
|
if (!storage.get(STORAGE_KEY.AUTHED)) {
|
|
authStore.openLoginModal()
|
|
return "/"
|
|
}
|
|
|
|
const userStore = useUserStore()
|
|
if (!userStore.user) {
|
|
try {
|
|
await userStore.getMyProfile()
|
|
} catch {
|
|
return "/"
|
|
}
|
|
}
|
|
if (to.matched.some((record) => record.meta.requiresSuperAdmin)) {
|
|
if (!userStore.isSuperAdmin) {
|
|
return "/"
|
|
}
|
|
} else if (to.matched.some((record) => record.meta.requiresTeacherAdmin)) {
|
|
if (!userStore.isTeacherOrAbove) {
|
|
return "/"
|
|
}
|
|
} else if (to.matched.some((record) => record.meta.requiresProblemPermission)) {
|
|
if (!userStore.hasProblemPermission) {
|
|
return "/"
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
app.mount("#app")
|
|
|
|
if (import.meta.env.PUBLIC_ICONIFY_URL) {
|
|
addAPIProvider("", {
|
|
resources: [import.meta.env.PUBLIC_ICONIFY_URL],
|
|
})
|
|
}
|