fix: 打卡后即时推送 + 设置页展示自动同步失败原因
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
// 多端同步引擎:全量差异对比 + 记录级新者胜 + 自然键去重 + 外键重映射 + 软删除墓碑
|
||||
// 实时性:本地变更 3 秒内推送;服务端变更通过 SSE 秒级通知其他端;60 秒轮询兜底
|
||||
import { ref } from 'vue'
|
||||
import Dexie, { liveQuery } from 'dexie'
|
||||
import { db } from '../db/schema'
|
||||
import { getSetting, setSetting } from '../db/repo'
|
||||
@@ -7,6 +8,9 @@ import { getCloudCreds } from '../db/auth'
|
||||
import { nowLocalISO } from '../lib/date'
|
||||
import { notifyAttendanceChanged } from '../lib/bus'
|
||||
|
||||
// 最近一次自动同步的错误(设置页展示用)
|
||||
export const syncLastError = ref('')
|
||||
|
||||
const TABLES = ['project', 'work_log', 'log_item', 'attendance', 'weekly_note', 'setting', 'memo', 'credential', 'transaction']
|
||||
|
||||
// 本地敏感或临时性的设置不参与同步
|
||||
@@ -150,7 +154,10 @@ export async function autoSyncNow(): Promise<void> {
|
||||
try {
|
||||
if (!(await isSyncConfigured())) return
|
||||
await runSync(await loadSyncConfig())
|
||||
} catch { /* 自动同步静默失败,等待下次触发 */ }
|
||||
syncLastError.value = ''
|
||||
} catch (e) {
|
||||
syncLastError.value = e instanceof Error ? e.message : String(e)
|
||||
}
|
||||
}
|
||||
|
||||
// 实时触发:本地任何数据变更 3 秒后自动推送(Dexie 4 核心 liveQuery,跨全部业务表)
|
||||
|
||||
@@ -13,7 +13,7 @@ import { downloadCsv } from '../lib/csv'
|
||||
import { hhmm, parseDateStr, todayStr } from '../lib/date'
|
||||
import { computeDay } from '../domain/attendance'
|
||||
import { changeLoginPassword, deleteCurrentUser, getSession } from '../db/auth'
|
||||
import { ensureCloudBinding, getSyncBase, getSyncLastTime, syncWithStoredConfig, type SyncResult } from '../sync/engine'
|
||||
import { ensureCloudBinding, getSyncBase, getSyncLastTime, syncWithStoredConfig, syncLastError, enableRealtimeSync, stopRealtime, type SyncResult } from '../sync/engine'
|
||||
import { getCloudCreds } from '../db/auth'
|
||||
import { showToast } from '../lib/toast'
|
||||
|
||||
@@ -41,6 +41,7 @@ const syncBase = ref('')
|
||||
const cloudUser = ref('')
|
||||
const syncStatus = ref('')
|
||||
const syncError = ref('')
|
||||
const autoSyncErr = ref('')
|
||||
const syncing = ref(false)
|
||||
const lastSync = ref('')
|
||||
|
||||
@@ -48,8 +49,12 @@ async function loadSyncInfo() {
|
||||
syncBase.value = await getSyncBase()
|
||||
cloudUser.value = getCloudCreds()?.username || ''
|
||||
lastSync.value = await getSyncLastTime()
|
||||
loadError.value = syncLastError.value
|
||||
const conf = await isSyncConfigured()
|
||||
autoOn.value = conf
|
||||
}
|
||||
|
||||
|
||||
async function saveSyncConfig() {
|
||||
await setSetting('sync_base_url', syncBase.value.trim())
|
||||
showToast('同步地址已保存')
|
||||
@@ -68,12 +73,14 @@ async function rebindCloud() {
|
||||
async function doSyncNow() {
|
||||
if (syncing.value) return
|
||||
syncError.value = ''
|
||||
autoSyncErr.value = syncLastError.value
|
||||
syncing.value = true
|
||||
try {
|
||||
await saveSyncConfig()
|
||||
const result: SyncResult = await syncWithStoredConfig()
|
||||
lastSync.value = result.at
|
||||
syncStatus.value = '推送 ' + result.pushed + ' 条 · 拉取 ' + result.pulled + ' 条 · 删除 ' + result.removed + ' 条'
|
||||
autoSyncErr.value = ''
|
||||
showToast('同步完成')
|
||||
} catch (e) {
|
||||
syncError.value = e instanceof Error ? e.message : '同步失败'
|
||||
@@ -357,6 +364,8 @@ async function doImport() {
|
||||
</div>
|
||||
<div v-if="syncStatus" class="muted acc-line">上次同步:{{ lastSync || '--' }} · {{ syncStatus }}</div>
|
||||
<div v-if="syncError" class="form-error">{{ syncError }}</div>
|
||||
<div v-if="autoSyncErr" class="form-error">最近自动同步失败:{{ autoSyncErr }}</div>
|
||||
<div v-if="autoSyncErr" class="form-error">最近自动同步失败:{{ autoSyncErr }}(可点「立即同步」重试)</div>
|
||||
</div>
|
||||
|
||||
<div class="card section">
|
||||
|
||||
Reference in New Issue
Block a user