1 parent
23844ae301
commit
d25b5dbe6d
268 files changed
+3684
-8861
No files matched your search
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
breakpointsTailwind,
|
||||
useBreakpoints as useVueUseBreakpoints,
|
||||
} from "@vueuse/core"
|
||||
import { breakpointsTailwind, useBreakpoints as useVueUseBreakpoints } from "@vueuse/core"
|
||||
|
||||
/**
|
||||
* 响应式断点检测 composable
|
||||
|
||||
@@ -11,9 +11,7 @@ import { Chart as ChartJS } from "chart.js"
|
||||
export function useChartTheme() {
|
||||
const isDark = useDark()
|
||||
|
||||
const textColor = computed(() =>
|
||||
isDark.value ? "rgba(255, 255, 255, 0.75)" : "#606266",
|
||||
)
|
||||
const textColor = computed(() => (isDark.value ? "rgba(255, 255, 255, 0.75)" : "#606266"))
|
||||
const gridColor = computed(() =>
|
||||
isDark.value ? "rgba(255, 255, 255, 0.12)" : "rgba(0, 0, 0, 0.1)",
|
||||
)
|
||||
|
||||
@@ -47,21 +47,16 @@ export function useCollabDoc() {
|
||||
if (doc) stop()
|
||||
const myGeneration = ++generation
|
||||
|
||||
const [
|
||||
Y,
|
||||
awarenessProtocol,
|
||||
syncProtocol,
|
||||
encoding,
|
||||
decoding,
|
||||
{ yCollab },
|
||||
] = await Promise.all([
|
||||
import("yjs"),
|
||||
import("y-protocols/awareness"),
|
||||
import("y-protocols/sync"),
|
||||
import("lib0/encoding"),
|
||||
import("lib0/decoding"),
|
||||
import("y-codemirror.next"),
|
||||
])
|
||||
const [Y, awarenessProtocol, syncProtocol, encoding, decoding, { yCollab }] = await Promise.all(
|
||||
[
|
||||
import("yjs"),
|
||||
import("y-protocols/awareness"),
|
||||
import("y-protocols/sync"),
|
||||
import("lib0/encoding"),
|
||||
import("lib0/decoding"),
|
||||
import("y-codemirror.next"),
|
||||
],
|
||||
)
|
||||
|
||||
// 等 chunk 的这段时间里房间关了(或者又开了新的一轮),整个放弃
|
||||
if (myGeneration !== generation) return
|
||||
@@ -112,11 +107,7 @@ export function useCollabDoc() {
|
||||
detachDocUpdate = () => doc?.off("update", onDocUpdate)
|
||||
|
||||
const onAwarenessUpdate = (
|
||||
{
|
||||
added,
|
||||
updated,
|
||||
removed,
|
||||
}: { added: number[]; updated: number[]; removed: number[] },
|
||||
{ added, updated, removed }: { added: number[]; updated: number[]; removed: number[] },
|
||||
origin: any,
|
||||
) => {
|
||||
if (origin === "remote") return
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { useConfigStore } from "shared/store/config"
|
||||
import { useUserStore } from "shared/store/user"
|
||||
import {
|
||||
useConfigWebSocket,
|
||||
type ConfigUpdate,
|
||||
} from "shared/composables/websocket"
|
||||
import { useConfigWebSocket, type ConfigUpdate } from "shared/composables/websocket"
|
||||
|
||||
/**
|
||||
* 收 /ws/config 的站点配置广播,写进 configStore —— 超管改完配置,所有开着页面
|
||||
@@ -19,8 +16,7 @@ export function useConfigUpdate() {
|
||||
const handleConfigUpdate = (data: ConfigUpdate) => {
|
||||
// 认不出来的键直接忽略:后端将来多推一个字段,不该把 store 撑出个野字段
|
||||
if (!(data.key in configStore.config)) return
|
||||
;(configStore.config as unknown as Record<string, unknown>)[data.key] =
|
||||
data.value
|
||||
;(configStore.config as unknown as Record<string, unknown>)[data.key] = data.value
|
||||
// getConfig() 里也是这么设的,站点改名后标签页跟着变,别只更新页面里那份
|
||||
if (data.key === "websiteName") document.title = data.value
|
||||
}
|
||||
|
||||
@@ -40,10 +40,7 @@ export function useDarkTransition() {
|
||||
.ready.then(() => {
|
||||
document.documentElement.animate(
|
||||
{
|
||||
clipPath: [
|
||||
`circle(0px at ${x}px ${y}px)`,
|
||||
`circle(${radius}px at ${x}px ${y}px)`,
|
||||
],
|
||||
clipPath: [`circle(0px at ${x}px ${y}px)`, `circle(${radius}px at ${x}px ${y}px)`],
|
||||
},
|
||||
{
|
||||
duration: 400,
|
||||
|
||||
@@ -64,9 +64,7 @@ export function useHiddenStudents(storageKey: string) {
|
||||
// 把已经到期的清掉再落一次盘,否则这张表只增不减
|
||||
const now = Date.now()
|
||||
const cleaned = Object.fromEntries(
|
||||
Object.entries(hiddenStudents.value).filter(
|
||||
([, expiresAt]) => expiresAt > now,
|
||||
),
|
||||
Object.entries(hiddenStudents.value).filter(([, expiresAt]) => expiresAt > now),
|
||||
)
|
||||
hiddenStudents.value = cleaned
|
||||
save(cleaned)
|
||||
|
||||
@@ -5,10 +5,10 @@ export type TutorialType = "python" | "c"
|
||||
|
||||
// 模块级单例:学习页写入、导航栏读取,必须共用同一个响应式引用,
|
||||
// 否则导航栏的链接不会随学习进度更新
|
||||
const learnStep = useStorage<Record<TutorialType, number>>(
|
||||
STORAGE_KEY.LEARN_CURRENT_STEP,
|
||||
{ python: 1, c: 1 },
|
||||
)
|
||||
const learnStep = useStorage<Record<TutorialType, number>>(STORAGE_KEY.LEARN_CURRENT_STEP, {
|
||||
python: 1,
|
||||
c: 1,
|
||||
})
|
||||
|
||||
export function useLearnProgress() {
|
||||
return { learnStep }
|
||||
|
||||
@@ -27,11 +27,7 @@ export function usePagination<T extends Record<string, any>>(
|
||||
initialQuery: Omit<T, "page" | "limit"> = {} as Omit<T, "page" | "limit">,
|
||||
options: UsePaginationOptions = {},
|
||||
) {
|
||||
const {
|
||||
defaultLimit = 10,
|
||||
defaultPage = 1,
|
||||
resetPageOnChange = true,
|
||||
} = options
|
||||
const { defaultLimit = 10, defaultPage = 1, resetPageOnChange = true } = options
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
@@ -9,7 +9,5 @@ import { RARITY_TEXT_COLOR } from "utils/constants"
|
||||
*/
|
||||
export function useRarityColor() {
|
||||
const isDark = useDark()
|
||||
return computed(() =>
|
||||
isDark.value ? RARITY_TEXT_COLOR.dark : RARITY_TEXT_COLOR.light,
|
||||
)
|
||||
return computed(() => (isDark.value ? RARITY_TEXT_COLOR.dark : RARITY_TEXT_COLOR.light))
|
||||
}
|
||||
@@ -286,10 +286,7 @@ export function useMermaid() {
|
||||
const renderSuccess = ref(false)
|
||||
let renderGeneration = 0
|
||||
|
||||
const renderFlowchart = async (
|
||||
container: HTMLElement | null,
|
||||
mermaidCode: string,
|
||||
) => {
|
||||
const renderFlowchart = async (container: HTMLElement | null, mermaidCode: string) => {
|
||||
renderError.value = null
|
||||
renderSuccess.value = false
|
||||
|
||||
@@ -308,10 +305,7 @@ export function useMermaid() {
|
||||
renderSuccess.value = true
|
||||
} catch (error) {
|
||||
if (gen !== renderGeneration) return
|
||||
renderError.value =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "流程图渲染失败,请检查代码格式"
|
||||
renderError.value = error instanceof Error ? error.message : "流程图渲染失败,请检查代码格式"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,11 +35,7 @@ function handleForceLogout(reason: string) {
|
||||
/**
|
||||
* WebSocket 连接状态
|
||||
*/
|
||||
export type ConnectionStatus =
|
||||
| "disconnected"
|
||||
| "connecting"
|
||||
| "connected"
|
||||
| "error"
|
||||
export type ConnectionStatus = "disconnected" | "connecting" | "connected" | "error"
|
||||
|
||||
/**
|
||||
* WebSocket 消息类型
|
||||
@@ -72,9 +68,7 @@ function channelUrl(path: string) {
|
||||
/**
|
||||
* WebSocket 消息处理器
|
||||
*/
|
||||
export type MessageHandler<T extends WebSocketMessage = WebSocketMessage> = (
|
||||
data: T,
|
||||
) => void
|
||||
export type MessageHandler<T extends WebSocketMessage = WebSocketMessage> = (data: T) => void
|
||||
|
||||
/**
|
||||
* WebSocket 基础连接管理类
|
||||
@@ -113,8 +107,7 @@ export class BaseWebSocket<T extends WebSocketMessage = WebSocketMessage> {
|
||||
|
||||
if (
|
||||
this.ws &&
|
||||
(this.ws.readyState === WebSocket.OPEN ||
|
||||
this.ws.readyState === WebSocket.CONNECTING)
|
||||
(this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)
|
||||
) {
|
||||
return
|
||||
}
|
||||
@@ -185,9 +178,7 @@ export class BaseWebSocket<T extends WebSocketMessage = WebSocketMessage> {
|
||||
// 收尾由 disconnect() 自己做 —— 也就不会再像以前那样「断完立刻重连」
|
||||
if (ws !== this.ws) return
|
||||
this.ws = null
|
||||
console.log(
|
||||
`[WebSocket] 连接关闭: code=${event.code}, reason=${event.reason}`,
|
||||
)
|
||||
console.log(`[WebSocket] 连接关闭: code=${event.code}, reason=${event.reason}`)
|
||||
this.status.value = "disconnected"
|
||||
this.stopHeartbeat()
|
||||
this.onDisconnected(event)
|
||||
@@ -214,9 +205,7 @@ export class BaseWebSocket<T extends WebSocketMessage = WebSocketMessage> {
|
||||
RECONNECT_MAX_DELAY,
|
||||
)
|
||||
const delay = Math.round(base * (0.5 + Math.random() * 0.5))
|
||||
console.log(
|
||||
`[WebSocket] 将在 ${delay}ms 后重连 (第 ${this.reconnectAttempts} 次)`,
|
||||
)
|
||||
console.log(`[WebSocket] 将在 ${delay}ms 后重连 (第 ${this.reconnectAttempts} 次)`)
|
||||
this.reconnectTimer = window.setTimeout(() => {
|
||||
this.reconnectTimer = null
|
||||
this.connect()
|
||||
@@ -238,8 +227,7 @@ export class BaseWebSocket<T extends WebSocketMessage = WebSocketMessage> {
|
||||
if (this.closedByUser) return
|
||||
if (
|
||||
this.ws &&
|
||||
(this.ws.readyState === WebSocket.OPEN ||
|
||||
this.ws.readyState === WebSocket.CONNECTING)
|
||||
(this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)
|
||||
) {
|
||||
return
|
||||
}
|
||||
@@ -481,10 +469,7 @@ export interface SubmissionUpdate extends WebSocketMessage {
|
||||
*
|
||||
* 每次调用都新建一条连接(和原来一致,不是单例),并在组件卸载时摘掉 handler、断开。
|
||||
*/
|
||||
function useChannel<T extends WebSocketMessage>(
|
||||
path: string,
|
||||
handler?: MessageHandler<T>,
|
||||
) {
|
||||
function useChannel<T extends WebSocketMessage>(path: string, handler?: MessageHandler<T>) {
|
||||
const ws = new BaseWebSocket<T>(path)
|
||||
|
||||
// 同步注册,不放 onMounted:调用方(如 useConfigUpdate)在 setup 阶段就 connect(),
|
||||
@@ -521,9 +506,7 @@ export interface SubmissionUpdate extends WebSocketMessage {
|
||||
}
|
||||
|
||||
/** 判题进度。subscribe(submissionId) 认领,断线重连会自动补订阅 */
|
||||
export function useSubmissionWebSocket(
|
||||
handler?: MessageHandler<SubmissionUpdate>,
|
||||
) {
|
||||
export function useSubmissionWebSocket(handler?: MessageHandler<SubmissionUpdate>) {
|
||||
return useChannel<SubmissionUpdate>("/ws/submissions", handler)
|
||||
}
|
||||
|
||||
@@ -548,9 +531,7 @@ export interface FlowchartEvaluationUpdate extends WebSocketMessage {
|
||||
* 流程图评分进度。和判题走的是**同一条** `/ws/submissions` ——
|
||||
* 服务端按 submissionId 分辨是代码提交还是流程图,这里只是换一套消息类型。
|
||||
*/
|
||||
export function useFlowchartWebSocket(
|
||||
handler?: MessageHandler<FlowchartEvaluationUpdate>,
|
||||
) {
|
||||
export function useFlowchartWebSocket(handler?: MessageHandler<FlowchartEvaluationUpdate>) {
|
||||
return useChannel<FlowchartEvaluationUpdate>("/ws/submissions", handler)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user