Add installable PWA shell with safe updates and offline status
This commit is contained in:
1 parent
64915a7b94
commit
1562519f08
18 files changed
+310
-5
No files matched your search
@@ -0,0 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { installApp, installPrompt, online, waitingWorker } from './pwa'
|
||||
import { flushAll, readyToReload, toast } from './workspace'
|
||||
|
||||
const busy = ref(false)
|
||||
const activated = ref(false)
|
||||
|
||||
async function update() {
|
||||
const worker = waitingWorker.value
|
||||
if ((!worker && !activated.value) || busy.value) return
|
||||
busy.value = true
|
||||
try {
|
||||
await flushAll()
|
||||
if (!readyToReload()) {
|
||||
toast('请先完成保存、图片上传或文件操作,再更新应用')
|
||||
return
|
||||
}
|
||||
if (!activated.value && worker) {
|
||||
// 等待新版激活后,仅刷新主动点击更新的页面。
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const finish = () => {
|
||||
if (worker.state !== 'activated' && worker.state !== 'redundant') return
|
||||
clearTimeout(timer)
|
||||
worker.removeEventListener('statechange', finish)
|
||||
if (worker.state === 'activated') resolve()
|
||||
else reject(new Error('新版本激活失败'))
|
||||
}
|
||||
const timer = setTimeout(() => {
|
||||
worker.removeEventListener('statechange', finish)
|
||||
reject(new Error('等待新版本超时'))
|
||||
}, 15000)
|
||||
worker.addEventListener('statechange', finish)
|
||||
worker.postMessage('ACTIVATE')
|
||||
finish()
|
||||
})
|
||||
activated.value = true
|
||||
}
|
||||
// 激活期间仍可能继续输入,刷新前再次确认;保留按钮供保存后重试。
|
||||
if (readyToReload()) location.reload()
|
||||
else toast('仍有未完成的保存或操作,请完成后再次点击刷新')
|
||||
} catch {
|
||||
toast('暂时无法更新,请稍后重试')
|
||||
} finally {
|
||||
busy.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!online || waitingWorker || activated || installPrompt" class="rm-app-status" role="status">
|
||||
<span v-if="!online">离线,无法加载或保存笔记</span>
|
||||
<template v-else-if="waitingWorker || activated">
|
||||
<span>有新版本</span>
|
||||
<button class="rm-btn" :disabled="busy" @click="update">{{ busy ? '正在保存…' : '保存并刷新' }}</button>
|
||||
</template>
|
||||
<template v-else-if="installPrompt">
|
||||
<span>将 RawMark 添加到主屏幕</span>
|
||||
<button class="rm-btn" @click="installApp">安装</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
Reference in new issue
Block a user