fix(data): 覆盖式导入与快照恢复前自动备份

- importJson / restoreSnapshot 覆盖前先写一份当前数据快照,误操作可回退
- 导入校验增加 id 唯一性检查,宽容读取路径保留首条
- 快照索引对同一时间点的重复写入去重
- 落盘失败时翻转 persistent,恢复后自动撤除告警
- 备份面板提示导入前数据已自动备份
This commit is contained in:
chenshoulin
2026-10-19 17:20:20 +08:00
parent 12c5346f75
commit ede4bfe88f
8 changed files with 214 additions and 14 deletions
+23
View File
@@ -123,6 +123,17 @@ describe('coerceTaskList', () => {
expect(coerceTaskList(null)).toEqual([])
expect(coerceTaskList({})).toEqual([])
})
it('重复 id 只保留先出现的那条', () => {
const list = coerceTaskList([
validTask({ id: 'dup', title: '第一条' }),
validTask({ id: 'dup', title: '第二条' }),
validTask({ id: 'other' }),
])
expect(list.map((task) => task.id)).toEqual(['dup', 'other'])
expect(list[0]?.title).toBe('第一条')
})
})
describe('parsePersistedState', () => {
@@ -240,6 +251,18 @@ describe('导入校验(严格)', () => {
)
})
it('id 重复时整体拒绝,并指出重复的两条', () => {
const duplicated = [
validTask({ id: 'same' }),
validTask({ id: 'other' }),
validTask({ id: 'same' }),
]
expect(() => validateImportPayload({ tasks: duplicated })).toThrow(
/第 3 条与第 1 条任务的 id 相同(same)/,
)
})
it('缺少 tasks 数组时抛错', () => {
expect(() => validateImportPayload({ schemaVersion: 1 })).toThrow(/缺少 tasks 数组/)
})