diff --git a/proto/main.proto b/proto/main.proto index 680e8da..e2d0e3e 100644 --- a/proto/main.proto +++ b/proto/main.proto @@ -1875,7 +1875,7 @@ message SetScreenSoundRsp { message MapItem { string kind = 1; - int32 itemID = 2; + string itemID = 2; string label = 3; int32 x = 4; int32 y = 5; @@ -1895,7 +1895,7 @@ message GetGameMapRsp { message UpdateGameMapItemReq { int32 gameID = 1; string kind = 2; - int32 itemID = 3; + string itemID = 3; int32 x = 4; int32 y = 5; bool hidden = 6; @@ -2008,7 +2008,7 @@ message ParticipationRsp { } message Team { - int32 ID = 1; + string ID = 1; string name = 2; string status = 3; string password = 4; @@ -2076,7 +2076,7 @@ message GetGameResultsRsp { message GameReview { int32 ID = 1; int32 gameID = 2; - int32 teamID = 3; + string teamID = 3; string team_name = 4; int32 rating = 5; string text = 6; @@ -2088,7 +2088,7 @@ message GameReview { message CreateGameReviewReq { int32 gameID = 1; - int32 teamID = 2; + string teamID = 2; string password = 3; int32 rating = 4; string text = 5; @@ -2187,12 +2187,12 @@ message AddTeamReq { } message AddTeamRsp { - int32 ID = 1; + string ID = 1; string password = 2; } message UpdateTeamReq { - int32 ID = 1; + string ID = 1; string name = 2; } @@ -2200,14 +2200,14 @@ message UpdateTeamRsp { } message DeleteTeamReq { - int64 ID = 1; + string ID = 1; } message DeleteTeamRsp { } message GiveTeamApplicationsReq { - int64 ID = 1; + string ID = 1; string name = 2; } @@ -2215,7 +2215,7 @@ message GiveTeamApplicationsRsp { } message GetTeamStoryReq { - int64 ID = 1; + string ID = 1; string password = 2; } @@ -2231,7 +2231,7 @@ message TeamAction { } message AddTeamActionReq { - int64 ID = 1; + string ID = 1; string password = 2; string code = 3; } @@ -2240,14 +2240,14 @@ message AddTeamActionRsp { } message DeleteLastTeamActionReq { - int64 ID = 1; + string ID = 1; } message DeleteLastTeamActionRsp { } message GetTeamAnswersReq { - int64 ID = 1; + string ID = 1; string password = 2; } @@ -2256,7 +2256,7 @@ message GetTeamAnswersRsp { } message SubmitTeamAnswersReq { - int64 ID = 1; + string ID = 1; string password = 2; repeated Answer answers = 3; } @@ -2265,7 +2265,7 @@ message SubmitTeamAnswersRsp { } message SetTeamAnswerScoreReq { - int64 ID = 1; + string ID = 1; string questionCode = 2; // Балл; отсутствует — сбросить выставленный балл optional int32 score = 3; @@ -2404,7 +2404,7 @@ message DeviceHeartbeatReq { string deviceID = 1; string connectionID = 2; optional int32 organizerGameID = 3; - optional int32 teamID = 4; + optional string teamID = 4; string password = 5; string screenID = 6; string accessToken = 7; @@ -2439,7 +2439,7 @@ message DeviceConnection { string userAgent = 5; bool connected = 6; optional int32 gameID = 7; - optional int32 teamID = 8; + optional string teamID = 8; optional int32 screenID = 9; string kind = 10; // browser, organizer, team, screen } diff --git a/src/api/generated/crabs/evening_detective_server/index.ts b/src/api/generated/crabs/evening_detective_server/index.ts index 92c2a68..3b66127 100644 --- a/src/api/generated/crabs/evening_detective_server/index.ts +++ b/src/api/generated/crabs/evening_detective_server/index.ts @@ -405,7 +405,7 @@ export type TeamAnswers = { }; export type Team = { - ID: number | undefined; + ID: string | undefined; name: string | undefined; status: string | undefined; password: string | undefined; @@ -712,7 +712,7 @@ export type SetScreenSoundRsp = { export type MapItem = { kind: string | undefined; - itemID: number | undefined; + itemID: string | undefined; label: string | undefined; x: number | undefined; y: number | undefined; @@ -732,7 +732,7 @@ export type GetGameMapRsp = { export type UpdateGameMapItemReq = { gameID: number | undefined; kind: string | undefined; - itemID: number | undefined; + itemID: string | undefined; x: number | undefined; y: number | undefined; hidden: boolean | undefined; @@ -895,7 +895,7 @@ export type GetGameResultsRsp = { export type GameReview = { ID: number | undefined; gameID: number | undefined; - teamID: number | undefined; + teamID: string | undefined; teamName: string | undefined; rating: number | undefined; text: string | undefined; @@ -907,7 +907,7 @@ export type GameReview = { export type CreateGameReviewReq = { gameID: number | undefined; - teamID: number | undefined; + teamID: string | undefined; password: string | undefined; rating: number | undefined; text: string | undefined; @@ -1007,12 +1007,12 @@ export type AddTeamReq = { }; export type AddTeamRsp = { - ID: number | undefined; + ID: string | undefined; password: string | undefined; }; export type UpdateTeamReq = { - ID: number | undefined; + ID: string | undefined; name: string | undefined; }; @@ -1020,14 +1020,14 @@ export type UpdateTeamRsp = { }; export type DeleteTeamReq = { - ID: number | undefined; + ID: string | undefined; }; export type DeleteTeamRsp = { }; export type GiveTeamApplicationsReq = { - ID: number | undefined; + ID: string | undefined; name: string | undefined; }; @@ -1035,7 +1035,7 @@ export type GiveTeamApplicationsRsp = { }; export type GetTeamStoryReq = { - ID: number | undefined; + ID: string | undefined; password: string | undefined; }; @@ -1051,7 +1051,7 @@ export type TeamAction = { }; export type AddTeamActionReq = { - ID: number | undefined; + ID: string | undefined; password: string | undefined; code: string | undefined; }; @@ -1060,14 +1060,14 @@ export type AddTeamActionRsp = { }; export type DeleteLastTeamActionReq = { - ID: number | undefined; + ID: string | undefined; }; export type DeleteLastTeamActionRsp = { }; export type GetTeamAnswersReq = { - ID: number | undefined; + ID: string | undefined; password: string | undefined; }; @@ -1076,7 +1076,7 @@ export type GetTeamAnswersRsp = { }; export type SubmitTeamAnswersReq = { - ID: number | undefined; + ID: string | undefined; password: string | undefined; answers: Answer[] | undefined; }; @@ -1085,7 +1085,7 @@ export type SubmitTeamAnswersRsp = { }; export type SetTeamAnswerScoreReq = { - ID: number | undefined; + ID: string | undefined; questionCode: string | undefined; // Балл; отсутствует — сбросить выставленный балл score?: number; @@ -1285,7 +1285,7 @@ export type DeviceHeartbeatReq = { deviceID: string | undefined; connectionID: string | undefined; organizerGameID?: number; - teamID?: number; + teamID?: string; password: string | undefined; screenID: string | undefined; accessToken: string | undefined; @@ -1322,7 +1322,7 @@ export type DeviceConnection = { userAgent: string | undefined; connected: boolean | undefined; gameID?: number; - teamID?: number; + teamID?: string; screenID?: number; kind: string | undefined; }; diff --git a/src/components/GamePage.vue b/src/components/GamePage.vue index 9d79fe7..d14d78e 100644 --- a/src/components/GamePage.vue +++ b/src/components/GamePage.vue @@ -81,7 +81,6 @@ async function setActiveTab(value: string) { if (!isGameTab(value) || (value === 'state' ? !canViewState.value : !canManageGame.value)) return activeTab.value = value await router.replace({ query: { ...route.query, tab: value } }) - if (value === 'answers') await loadGameAnswers() } function onStateTabKeydown(event: KeyboardEvent) { @@ -546,7 +545,7 @@ async function unbindScreen(screen: ScreenState) { await getGameScreens() } -async function toTeamStory(id: number, password: string, newTab: boolean = false) { +async function toTeamStory(id: string, password: string, newTab: boolean = false) { const uri = '/team-story/' + id + '?password=' + password if (newTab) { window.open(uri, '_blank') @@ -687,7 +686,7 @@ async function updateGame() { } const giveApplicationTeam = ref({ - ID: 0, + ID: '', name: '', status: '', password: '', @@ -703,7 +702,7 @@ const giveApplicationTeam = ref({ const deletedTeamName = ref('') const deletedTeam = ref({ - ID: 0, + ID: '', name: '', status: '', password: '', @@ -778,7 +777,7 @@ async function deleteGame() { router.push('/games') } -function getTeamStoryURL(id: number, password: string): string { +function getTeamStoryURL(id: string, password: string): string { const url = new URL(`/team-story/${id}`, window.location.origin) url.searchParams.set('password', password) return url.toString() @@ -866,7 +865,7 @@ const answersTeams = ref([]) // Баллы по ключу "teamID:questionCode" (undefined — балл не выставлен) const scores = ref>({}) -function scoreKey(teamID: number | undefined, questionCode: string | undefined): string { +function scoreKey(teamID: string | undefined, questionCode: string | undefined): string { return (teamID ?? '') + ':' + (questionCode ?? '') } @@ -920,9 +919,13 @@ async function saveAllScores() { await loadGameAnswers() } -if (canManageGame.value && activeTab.value === 'answers') { - loadGameAnswers() -} +watch( + [canManageGame, activeTab], + ([canManage, tab]) => { + if (canManage && tab === 'answers') void loadGameAnswers() + }, + { immediate: true }, +) function getCurrentUTC(): Date { const now = new Date() diff --git a/src/components/GameTeamsPanel.vue b/src/components/GameTeamsPanel.vue index 68588bd..0dbcc14 100644 --- a/src/components/GameTeamsPanel.vue +++ b/src/components/GameTeamsPanel.vue @@ -12,7 +12,7 @@ defineProps<{ const emit = defineEmits<{ add: [] 'open-qr': [team: Team] - preview: [id: number, password: string] + preview: [id: string, password: string] delete: [team: Team] 'give-application': [team: Team, application: Application] }>() diff --git a/src/components/TeamStoryPage.vue b/src/components/TeamStoryPage.vue index 0760ef7..2cd311f 100644 --- a/src/components/TeamStoryPage.vue +++ b/src/components/TeamStoryPage.vue @@ -25,9 +25,9 @@ const authStore = useAuthStore() const client = getAuthClient() const message = useMessage() const route = useRoute() -const teamId = route.params.id +const teamId = String(route.params.id) const password = route.query.password -useDeviceContext(() => ({ teamID: Number(teamId), password: typeof password === 'string' ? password : undefined })) +useDeviceContext(() => ({ teamID: teamId, password: typeof password === 'string' ? password : undefined })) const newPlacesCount = ref(0) const actions = ref([]) @@ -78,7 +78,7 @@ async function getStory() { let res try { res = await client.GetTeamStory({ - ID: Number(teamId), + ID: teamId, password: password as string, }) } catch (err) { @@ -131,7 +131,7 @@ getAnswers() async function addAction(newCode: string): Promise { try { await client.AddTeamAction({ - ID: Number(teamId), + ID: teamId, password: password as string, code: newCode, }) @@ -165,7 +165,7 @@ async function getAnswers() { let res try { res = await client.GetTeamAnswers({ - ID: Number(teamId), + ID: teamId, password: password as string, }) } catch (err) { @@ -183,7 +183,7 @@ async function getAnswers() { async function submitAnswers() { await client.SubmitTeamAnswers({ - ID: Number(teamId), + ID: teamId, password: password as string, answers: (story.value.questions || []).map((question) => ({ questionCode: question.code, @@ -241,7 +241,7 @@ async function submitReview() { reviewLoading.value = true await client.CreateGameReview({ gameID: Number(game.value?.ID), - teamID: Number(teamId), + teamID: teamId, password: password as string, rating: reviewRating.value, difficulty: reviewDifficulty.value, @@ -255,7 +255,7 @@ async function submitReview() { async function deleteLast() { await client.DeleteLastTeamAction({ - ID: Number(teamId), + ID: teamId, }) await getStory() code.value = '' diff --git a/src/composables/__tests__/devicePresence.test.ts b/src/composables/__tests__/devicePresence.test.ts index c3a6719..e8b94f8 100644 --- a/src/composables/__tests__/devicePresence.test.ts +++ b/src/composables/__tests__/devicePresence.test.ts @@ -85,13 +85,13 @@ test('requests never overlap; latest context follows in-flight request; disabled fixture.documentEvents.dispatchEvent(new Event('visibilitychange')) fixture.callbacks.get(1)!() const lease = fixture.store.claim() - lease.set({ teamID: 2, password: 'secret' }) + lease.set({ teamID: '019a1234-5678-7abc-8def-000000000002', password: 'secret' }) await settle() assert.equal(requests.length, 1) first.resolve(json(true)) await settle() assert.equal(requests.length, 2) - assert.equal(requests[1].teamID, 2) + assert.equal(requests[1].teamID, '019a1234-5678-7abc-8def-000000000002') assert.equal(requests[0].deviceID, requests[1].deviceID) assert.equal(requests[0].connectionID, requests[1].connectionID) globalThis.fetch = async () => json(false) diff --git a/src/stores/__tests__/devicePresence.test.ts b/src/stores/__tests__/devicePresence.test.ts index 3840f3c..6bfe8ad 100644 --- a/src/stores/__tests__/devicePresence.test.ts +++ b/src/stores/__tests__/devicePresence.test.ts @@ -9,12 +9,12 @@ test('page leases clear context and reject late updates after navigation', () => setActivePinia(createPinia()) const store = useDevicePresenceStore() const player = store.claim() - player.set({ teamID: 2, password: 'secret' }) - assert.equal(store.context.teamID, 2) + player.set({ teamID: '019a1234-5678-7abc-8def-000000000002', password: 'secret' }) + assert.equal(store.context.teamID, '019a1234-5678-7abc-8def-000000000002') const screen = store.claim() screen.set({ screenID: '3', accessToken: 'token' }) player.clear() - player.set({ teamID: 2, password: 'stale' }) + player.set({ teamID: '019a1234-5678-7abc-8def-000000000002', password: 'stale' }) assert.deepEqual(store.context, { screenID: '3', accessToken: 'token' }) screen.clear() screen.set({ screenID: '3', accessToken: 'stale' })