优化首屏
This commit is contained in:
@@ -9,11 +9,14 @@
|
||||
<script>
|
||||
window.localStorage.setItem("maxkbMaskTip", true)
|
||||
</script>
|
||||
|
||||
<% if (process.env.PUBLIC_MAXKB_URL) { %>
|
||||
<script
|
||||
async
|
||||
defer
|
||||
src="<%= process.env.PUBLIC_MAXKB_URL %>"
|
||||
></script>
|
||||
<% } %>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -72,7 +72,44 @@ export default defineConfig(({ envMode }) => {
|
||||
performance: {
|
||||
chunkSplit: {
|
||||
strategy: "split-by-module",
|
||||
override: {
|
||||
cacheGroups: {
|
||||
// 将大型编辑器库单独分包
|
||||
editor: {
|
||||
test: /[\\/]node_modules[\\/](codemirror|@codemirror|vue-codemirror|@wangeditor-next|md-editor-v3|y-codemirror\.next)[\\/]/,
|
||||
name: "vendor-editor",
|
||||
priority: 30,
|
||||
},
|
||||
// Chart.js 独立分包(包含 canvas-confetti)
|
||||
charts: {
|
||||
test: /[\\/]node_modules[\\/](chart\.js|vue-chartjs|@kurkle|canvas-confetti)[\\/]/,
|
||||
name: "vendor-charts",
|
||||
priority: 25,
|
||||
},
|
||||
// UI 框架(Naive UI 及其依赖)
|
||||
ui: {
|
||||
test: /[\\/]node_modules[\\/](naive-ui|@css-render|css-render|seemly|vooks|vueuc|treemate|vdirs|evtd)[\\/]/,
|
||||
name: "vendor-ui",
|
||||
priority: 20,
|
||||
},
|
||||
// Vue 生态
|
||||
vue: {
|
||||
test: /[\\/]node_modules[\\/](vue|vue-router|pinia|@vue|@vueuse)[\\/]/,
|
||||
name: "vendor-vue",
|
||||
priority: 15,
|
||||
},
|
||||
// 其他常用库
|
||||
common: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: "vendor-common",
|
||||
priority: 10,
|
||||
minChunks: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// 移除 console.log(生产环境)
|
||||
removeConsole: ["log"],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
||||
42
src/App.vue
42
src/App.vue
@@ -1,17 +1,41 @@
|
||||
<script setup lang="ts">
|
||||
import hljs from "highlight.js/lib/core"
|
||||
import c from "highlight.js/lib/languages/c"
|
||||
import cpp from "highlight.js/lib/languages/cpp"
|
||||
import python from "highlight.js/lib/languages/python"
|
||||
import { darkTheme, dateZhCN, zhCN } from "naive-ui"
|
||||
import "normalize.css"
|
||||
import "./index.css"
|
||||
|
||||
hljs.registerLanguage("c", c)
|
||||
hljs.registerLanguage("python", python)
|
||||
hljs.registerLanguage("cpp", cpp)
|
||||
|
||||
const isDark = useDark()
|
||||
|
||||
// 延迟加载 highlight.js,避免阻塞首屏
|
||||
let hljsInstance: any = null
|
||||
const loadHighlightJS = async () => {
|
||||
if (hljsInstance) return hljsInstance
|
||||
|
||||
const hljs = (await import("highlight.js/lib/core")).default
|
||||
const c = (await import("highlight.js/lib/languages/c")).default
|
||||
const cpp = (await import("highlight.js/lib/languages/cpp")).default
|
||||
const python = (await import("highlight.js/lib/languages/python")).default
|
||||
|
||||
hljs.registerLanguage("c", c)
|
||||
hljs.registerLanguage("python", python)
|
||||
hljs.registerLanguage("cpp", cpp)
|
||||
|
||||
hljsInstance = hljs
|
||||
return hljs
|
||||
}
|
||||
|
||||
// 在空闲时预加载
|
||||
onMounted(() => {
|
||||
if ("requestIdleCallback" in window) {
|
||||
requestIdleCallback(() => loadHighlightJS())
|
||||
} else {
|
||||
setTimeout(() => loadHighlightJS(), 1000)
|
||||
}
|
||||
})
|
||||
|
||||
provide(
|
||||
"hljs",
|
||||
computed(() => hljsInstance),
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -19,7 +43,7 @@ const isDark = useDark()
|
||||
:theme="isDark ? darkTheme : null"
|
||||
:locale="zhCN"
|
||||
:date-locale="dateZhCN"
|
||||
:hljs="hljs"
|
||||
:hljs="hljsInstance"
|
||||
>
|
||||
<n-message-provider>
|
||||
<router-view></router-view>
|
||||
|
||||
@@ -5,6 +5,27 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Bar } from "vue-chartjs"
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
Colors,
|
||||
} from "chart.js"
|
||||
|
||||
// 仅注册柱状图所需的 Chart.js 组件
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
Colors,
|
||||
)
|
||||
|
||||
const props = defineProps<{
|
||||
difficulty: { [key: string]: number }
|
||||
|
||||
@@ -5,6 +5,18 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Pie } from "vue-chartjs"
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
ArcElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
Colors,
|
||||
} from "chart.js"
|
||||
|
||||
// 仅注册饼图所需的 Chart.js 组件
|
||||
ChartJS.register(ArcElement, Title, Tooltip, Legend, Colors)
|
||||
|
||||
const props = defineProps<{
|
||||
tags: { [key: string]: number }
|
||||
}>()
|
||||
|
||||
@@ -8,9 +8,34 @@
|
||||
<script setup lang="ts">
|
||||
import type { ChartData, ChartOptions, TooltipItem } from "chart.js"
|
||||
import { Chart } from "vue-chartjs"
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
LineElement,
|
||||
PointElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
Colors,
|
||||
} from "chart.js"
|
||||
import { useAIStore } from "oj/store/ai"
|
||||
import { parseTime } from "utils/functions"
|
||||
|
||||
// 注册混合图表(Bar + Line)所需的 Chart.js 组件
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
LineElement,
|
||||
PointElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
Colors,
|
||||
)
|
||||
|
||||
const props = defineProps<{
|
||||
end: string
|
||||
}>()
|
||||
|
||||
@@ -6,7 +6,7 @@ export interface SyncStatusState {
|
||||
}
|
||||
|
||||
// 提供/注入的 key
|
||||
export const SYNC_STATUS_KEY = Symbol('syncStatus')
|
||||
export const SYNC_STATUS_KEY = Symbol("syncStatus")
|
||||
|
||||
// 创建同步状态
|
||||
export function createSyncStatus() {
|
||||
@@ -42,10 +42,10 @@ export function provideSyncStatus() {
|
||||
|
||||
// 注入同步状态
|
||||
export function injectSyncStatus() {
|
||||
const syncStatus = inject<ReturnType<typeof createSyncStatus>>(SYNC_STATUS_KEY)
|
||||
const syncStatus =
|
||||
inject<ReturnType<typeof createSyncStatus>>(SYNC_STATUS_KEY)
|
||||
if (!syncStatus) {
|
||||
throw new Error('syncStatus must be provided by a parent component')
|
||||
throw new Error("syncStatus must be provided by a parent component")
|
||||
}
|
||||
return syncStatus
|
||||
}
|
||||
|
||||
|
||||
@@ -197,7 +197,11 @@ defineExpose({
|
||||
{{ SYNC_MESSAGES.SYNCING_WITH(syncStatus.otherUser.value.name) }}
|
||||
</n-tag>
|
||||
<n-tag
|
||||
v-if="userStore.isSuperAdmin && !syncStatus.otherUser.value && syncStatus.hadConnection.value"
|
||||
v-if="
|
||||
userStore.isSuperAdmin &&
|
||||
!syncStatus.otherUser.value &&
|
||||
syncStatus.hadConnection.value
|
||||
"
|
||||
type="warning"
|
||||
>
|
||||
{{ SYNC_MESSAGES.STUDENT_LEFT }}
|
||||
|
||||
@@ -4,9 +4,19 @@ import { problem } from "oj/composables/problem"
|
||||
import { DIFFICULTY, JUDGE_STATUS } from "utils/constants"
|
||||
import { getACRateNumber, getTagColor, parseTime } from "utils/functions"
|
||||
import { Pie } from "vue-chartjs"
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
ArcElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
Colors,
|
||||
} from "chart.js"
|
||||
import { getProblemBeatRate } from "oj/api"
|
||||
import { isDesktop } from "shared/composables/breakpoints"
|
||||
import { registerChart } from "utils/registerChart"
|
||||
|
||||
// 仅注册饼图所需的 Chart.js 组件
|
||||
ChartJS.register(ArcElement, Title, Tooltip, Legend, Colors)
|
||||
|
||||
const beatRate = ref("0")
|
||||
|
||||
@@ -74,7 +84,6 @@ async function getBeatRate() {
|
||||
beatRate.value = res.data
|
||||
}
|
||||
|
||||
onBeforeMount(registerChart)
|
||||
onMounted(getBeatRate)
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,8 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import { Bar } from "vue-chartjs"
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
Colors,
|
||||
} from "chart.js"
|
||||
import { ChartType } from "utils/constants"
|
||||
import { Rank } from "utils/types"
|
||||
|
||||
// 仅注册柱状图所需的 Chart.js 组件
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
Colors,
|
||||
)
|
||||
|
||||
const props = defineProps<{ rankData: Rank[]; type: ChartType }>()
|
||||
|
||||
const data = computed(() => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { RouteRecordRaw } from "vue-router"
|
||||
import { registerChart } from "./utils/registerChart"
|
||||
|
||||
export const ojs: RouteRecordRaw = {
|
||||
path: "/",
|
||||
@@ -66,7 +65,6 @@ export const ojs: RouteRecordRaw = {
|
||||
{
|
||||
path: "rank",
|
||||
component: () => import("oj/rank/list.vue"),
|
||||
beforeEnter: registerChart,
|
||||
},
|
||||
{
|
||||
path: "announcement",
|
||||
@@ -97,7 +95,6 @@ export const ojs: RouteRecordRaw = {
|
||||
path: "ai-analysis",
|
||||
component: () => import("oj/ai/analysis.vue"),
|
||||
meta: { requiresAuth: true },
|
||||
beforeEnter: registerChart,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -89,8 +89,8 @@ const initSync = async () => {
|
||||
// 处理需要断开同步的情况
|
||||
if (
|
||||
(status.errorCode === SYNC_ERROR_CODES.SUPER_ADMIN_LEFT ||
|
||||
status.errorCode === SYNC_ERROR_CODES.MISSING_SUPER_ADMIN)
|
||||
&& !status.connected
|
||||
status.errorCode === SYNC_ERROR_CODES.MISSING_SUPER_ADMIN) &&
|
||||
!status.connected
|
||||
) {
|
||||
emit("syncClosed")
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export const SYNC_MESSAGES = {
|
||||
|
||||
// 类型定义
|
||||
type SyncState = "waiting" | "active" | "error"
|
||||
type SyncErrorCode = typeof SYNC_ERROR_CODES[keyof typeof SYNC_ERROR_CODES]
|
||||
type SyncErrorCode = (typeof SYNC_ERROR_CODES)[keyof typeof SYNC_ERROR_CODES]
|
||||
|
||||
interface UserInfo {
|
||||
name: string
|
||||
@@ -210,7 +210,9 @@ export function useCodeSync() {
|
||||
roomUsers,
|
||||
canSync: false,
|
||||
message:
|
||||
roomUsers === 1 ? SYNC_MESSAGES.WAITING_STUDENT : SYNC_MESSAGES.WAITING_ADMIN,
|
||||
roomUsers === 1
|
||||
? SYNC_MESSAGES.WAITING_STUDENT
|
||||
: SYNC_MESSAGES.WAITING_ADMIN,
|
||||
otherUser,
|
||||
},
|
||||
onStatusChange,
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import {
|
||||
ArcElement,
|
||||
BarElement,
|
||||
BarController,
|
||||
CategoryScale,
|
||||
Chart as ChartJS,
|
||||
Colors,
|
||||
Legend,
|
||||
LinearScale,
|
||||
LineController,
|
||||
Title,
|
||||
Tooltip,
|
||||
LineElement,
|
||||
PointElement,
|
||||
} from "chart.js"
|
||||
|
||||
let registered = false
|
||||
|
||||
export function registerChart() {
|
||||
if (registered) return
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
BarElement,
|
||||
BarController,
|
||||
ArcElement,
|
||||
LineElement,
|
||||
LineController,
|
||||
PointElement,
|
||||
Colors,
|
||||
Title,
|
||||
Tooltip,
|
||||
Legend,
|
||||
)
|
||||
registered = true
|
||||
}
|
||||
Reference in New Issue
Block a user