diff --git a/apps/notes/frontend/src/App.vue b/apps/notes/frontend/src/App.vue index 005702f..3522e33 100644 --- a/apps/notes/frontend/src/App.vue +++ b/apps/notes/frontend/src/App.vue @@ -239,7 +239,8 @@ async function submitPass() { await listRecordings() needPass.value = false authError.value = '' - refresh() + await refresh() + syncFromUrl() startPoll() } catch (e) { if (e.unauthorized) { @@ -257,6 +258,7 @@ function logout() { list.value = [] selected.value = null selectedId.value = null + history.replaceState(null, '', window.location.pathname) stopPoll() } @@ -298,12 +300,21 @@ async function refresh(silent = false) { async function select(id) { selectedId.value = id + // URL 同步:?id=N,方便刷新 / 分享 / bookmark + const q = new URLSearchParams(window.location.search) + q.set('id', String(id)) + history.replaceState(null, '', '?' + q.toString()) try { selected.value = await getRecording(id) } catch (e) { if (e.unauthorized) { logout(); return } } } +function syncFromUrl() { + const id = parseInt(new URLSearchParams(window.location.search).get('id')) + if (id && id !== selectedId.value) select(id) +} + function onFile(e) { const f = e.target.files?.[0] if (!f) return @@ -332,6 +343,7 @@ async function remove() { await deleteRecording(selectedId.value) selectedId.value = null selected.value = null + history.replaceState(null, '', window.location.pathname) await refresh() } catch (e) { alert(e.message) } } @@ -421,10 +433,19 @@ function stopPoll() { if (pollTimer) { clearInterval(pollTimer); pollTimer = null } } -onMounted(() => { - if (!needPass.value) { refresh(); startPoll() } +onMounted(async () => { + if (!needPass.value) { + await refresh() + syncFromUrl() + startPoll() + } + // 浏览器前进/后退按钮也同步 + window.addEventListener('popstate', syncFromUrl) +}) +onBeforeUnmount(() => { + stopPoll() + window.removeEventListener('popstate', syncFromUrl) }) -onBeforeUnmount(stopPoll)