看板「改 / 新的一节 / 清掉」和后台课堂作业的增改删,前后比较学生看到的那一节, 真变了才按班推 lesson_update(加了、去掉了、语言、顺序),走学生的 /ws/config,老师不收。 没点刷新又改会合并成一条。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0fd94ee8bf
commit
df8af40d61
12 files changed
+344
-14
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import { useConfigStore } from 'shared/store/config'
|
||||
import { useUserStore } from 'shared/store/user'
|
||||
import { useConfigWebSocket, type ConfigUpdate } from 'shared/composables/websocket'
|
||||
import { receiveLessonUpdate } from 'shared/composables/lessonUpdate'
|
||||
import { useConfigWebSocket, type ConfigChannelMessage } from 'shared/composables/websocket'
|
||||
|
||||
/**
|
||||
* 收 /ws/config 的站点配置广播,写进 configStore —— 超管改完配置,所有开着页面
|
||||
@@ -13,7 +14,12 @@ export function useConfigUpdate() {
|
||||
const configStore = useConfigStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const handleConfigUpdate = (data: ConfigUpdate) => {
|
||||
const handleConfigUpdate = (data: ConfigChannelMessage) => {
|
||||
// 同一条连接上的班级广播:老师改了这节课的题(只推给学生,见后端 classTopicOf)
|
||||
if (data.type === 'lesson_update') {
|
||||
receiveLessonUpdate(data)
|
||||
return
|
||||
}
|
||||
// 认不出来的键直接忽略:后端将来多推一个字段,不该把 store 撑出个野字段
|
||||
if (!(data.key in configStore.config)) return
|
||||
;(configStore.config as unknown as Record<string, unknown>)[data.key] = data.value
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { LessonUpdate } from '@oj2/contract'
|
||||
|
||||
/**
|
||||
* 课上老师改了这节课的题(/ws/config 推来的 lesson_update),等学生点「刷新」。
|
||||
* useConfigUpdate 收、LessonUpdateNotice 显示,两头不在一个组件里,所以放模块级。
|
||||
*/
|
||||
export const pendingLessonUpdate = shallowRef<LessonUpdate | null>(null)
|
||||
|
||||
type Item = LessonUpdate['problems'][number]
|
||||
|
||||
function minus(list: Item[], other: Item[]) {
|
||||
const ids = new Set(other.map((item) => item.problemDisplayId))
|
||||
return list.filter((item) => !ids.has(item.problemDisplayId))
|
||||
}
|
||||
|
||||
/**
|
||||
* 还没点刷新老师又改了一次:并成一条,免得第二条把第一次加的题盖掉。
|
||||
* 刚布置(还没刷新)又改 → 仍算刚布置,题目按最新的列;两次「改」→ 加的、去掉的互相抵消后合起来
|
||||
*/
|
||||
export function receiveLessonUpdate(next: LessonUpdate) {
|
||||
const prev = pendingLessonUpdate.value
|
||||
if (!prev || next.kind !== 'changed' || prev.kind === 'cleared') {
|
||||
pendingLessonUpdate.value = next
|
||||
return
|
||||
}
|
||||
if (prev.kind === 'assigned') {
|
||||
pendingLessonUpdate.value = { ...next, kind: 'assigned', added: [], removed: [], languageChanged: false, reordered: false }
|
||||
return
|
||||
}
|
||||
const merged: LessonUpdate = {
|
||||
...next,
|
||||
added: [...minus(prev.added, next.removed), ...minus(next.added, prev.removed)],
|
||||
removed: [...minus(prev.removed, next.added), ...minus(next.removed, prev.added)],
|
||||
languageChanged: prev.languageChanged || next.languageChanged,
|
||||
reordered: prev.reordered || next.reordered,
|
||||
}
|
||||
// 改回去了:等于没改
|
||||
const nothing = !merged.added.length && !merged.removed.length && !merged.languageChanged && !merged.reordered
|
||||
pendingLessonUpdate.value = nothing ? null : merged
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WS_AUTH_PROTOCOL } from '@oj2/contract'
|
||||
import { WS_AUTH_PROTOCOL, type LessonUpdate } from '@oj2/contract'
|
||||
import { createDiscreteApi } from 'naive-ui'
|
||||
import { ref, getCurrentScope, onScopeDispose, type Ref } from 'vue'
|
||||
|
||||
@@ -559,14 +559,19 @@ export interface ConfigUpdate extends WebSocketMessage {
|
||||
value: any
|
||||
}
|
||||
|
||||
/**
|
||||
* 这条通道上还有一种按班推的:老师改了这节课的题(学生才收得到,见契约 lessonUpdateSchema)
|
||||
*/
|
||||
export type ConfigChannelMessage = ConfigUpdate | LessonUpdate
|
||||
|
||||
/**
|
||||
* 站点配置广播。这条通道是**单向**的:只收后端广播。服务端的消息处理只认
|
||||
* ping / subscribe,客户端往这里推 config_update 会被回一个 error 帧 ——
|
||||
* 别拿返回值里的 subscribe 往这条通道上发东西。配置变更走 POST /admin/website,
|
||||
* 由后端广播给所有人。
|
||||
*/
|
||||
export function useConfigWebSocket(handler?: MessageHandler<ConfigUpdate>) {
|
||||
return useChannel<ConfigUpdate>('/ws/config', handler)
|
||||
export function useConfigWebSocket(handler?: MessageHandler<ConfigChannelMessage>) {
|
||||
return useChannel<ConfigChannelMessage>('/ws/config', handler)
|
||||
}
|
||||
|
||||
export interface CollabRequestItem {
|
||||
|
||||
Reference in new issue
Block a user