/** * 本地存储管理工具(含缓存层 + 云端 fire-and-forget 同步) */ const api = require('./api') const sync = require('./sync') // 异步同步人员到后端;失败自动入队,启动时 flush function _syncPerson(action, data) { const openid = wx.getStorageSync('openid') if (!openid) return sync.syncOrEnqueue({ kind: 'person', action, data }) } // 内存缓存 const _cache = { persons: null, anniversaries: null } function _invalidate() { _cache.persons = null _cache.anniversaries = null } /** * 存储人员数据 */ function savePersons(persons) { try { wx.setStorageSync('persons', persons) _cache.persons = persons return { success: true } } catch (e) { console.error('保存人员数据失败', e) return { success: false, error: e.message } } } /** * 获取人员数据 */ function getPersons() { if (_cache.persons !== null) return _cache.persons try { _cache.persons = wx.getStorageSync('persons') || [] return _cache.persons } catch (e) { console.error('获取人员数据失败', e) return [] } } /** * 根据ID获取人员 */ function getPersonById(id) { return getPersons().find(p => p.id === id) || null } /** * 添加人员 */ function addPerson(person) { const persons = getPersons() const newPerson = { id: generateId(), ...person, createTime: new Date().getTime(), updateTime: new Date().getTime() } persons.push(newPerson) const result = savePersons(persons) if (!result.success) return null _syncPerson('add', newPerson) return newPerson } /** * 更新人员 */ function updatePerson(id, updates) { const persons = getPersons() const index = persons.findIndex(p => p.id === id) if (index === -1) return false persons[index] = { ...persons[index], ...updates, updateTime: new Date().getTime() } const ok = savePersons(persons).success if (ok) _syncPerson('update', persons[index]) return ok } /** * 按姓名查找已有人员;找不到则创建一个新的 person(仅 name),返回 person 对象 * Why:方案 B 流程合并——用户在「添加纪念日」页直接输入姓名,不再强制先建人 */ function ensurePerson(name) { const trimmed = (name || '').trim() if (!trimmed) return null const existing = getPersons().find(p => p.name === trimmed) if (existing) return existing return addPerson({ name: trimmed }) } /** * 删除人员 */ function deletePerson(id) { const persons = getPersons() const ok = savePersons(persons.filter(p => p.id !== id)).success if (ok) _syncPerson('delete', { id }) return ok } /** * 存储纪念日数据 */ function saveAnniversaries(anniversaries) { try { wx.setStorageSync('anniversaries', anniversaries) _cache.anniversaries = anniversaries return { success: true } } catch (e) { console.error('保存纪念日数据失败', e) return { success: false, error: e.message } } } /** * 获取纪念日数据 */ function getAnniversaries() { if (_cache.anniversaries !== null) return _cache.anniversaries try { _cache.anniversaries = wx.getStorageSync('anniversaries') || [] return _cache.anniversaries } catch (e) { console.error('获取纪念日数据失败', e) return [] } } /** * 根据人员ID获取纪念日 */ function getAnniversariesByPersonId(personId) { return getAnniversaries().filter(a => a.personId === personId) } /** * 添加纪念日 */ function addAnniversary(anniversary) { const anniversaries = getAnniversaries() const newAnniversary = { id: generateId(), ...anniversary, createTime: new Date().getTime(), updateTime: new Date().getTime() } anniversaries.push(newAnniversary) const result = saveAnniversaries(anniversaries) return result.success ? newAnniversary : null } /** * 更新纪念日 */ function updateAnniversary(id, updates) { const anniversaries = getAnniversaries() const index = anniversaries.findIndex(a => a.id === id) if (index !== -1) { anniversaries[index] = { ...anniversaries[index], ...updates, updateTime: new Date().getTime() } return saveAnniversaries(anniversaries).success } return false } /** * 删除纪念日 */ function deleteAnniversary(id) { const anniversaries = getAnniversaries() return saveAnniversaries(anniversaries.filter(a => a.id !== id)).success } /** * 原子性删除人员及其所有纪念日 */ function deletePersonWithAnniversaries(personId) { try { const persons = getPersons().filter(p => p.id !== personId) const anniversaries = getAnniversaries().filter(a => a.personId !== personId) wx.setStorageSync('persons', persons) wx.setStorageSync('anniversaries', anniversaries) _cache.persons = persons _cache.anniversaries = anniversaries // 后端 delete person 会级联删除该 personId 的所有 anniversaries(在事务里),无需单独再调 _syncPerson('delete', { id: personId }) return true } catch (e) { console.error('删除人员及纪念日失败', e) _invalidate() // 缓存可能不一致,强制失效 return false } } /** * 生成唯一ID */ function generateId() { return 'id_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9) } /** * 导出数据 */ function exportData() { return { persons: getPersons(), anniversaries: getAnniversaries(), exportTime: new Date().getTime() } } /** * 验证人员数据结构 */ function _validatePerson(p) { return p && typeof p === 'object' && typeof p.id === 'string' && typeof p.name === 'string' } /** * 验证纪念日数据结构 */ function _validateAnniversary(a) { return a && typeof a === 'object' && typeof a.id === 'string' && typeof a.personId === 'string' && typeof a.solarMonth === 'number' && typeof a.solarDay === 'number' } /** * 导入数据(含验证) */ function importData(data) { try { if (!data || typeof data !== 'object') { return { success: false, error: '无效的数据格式' } } if (!Array.isArray(data.persons) || !Array.isArray(data.anniversaries)) { return { success: false, error: 'persons 和 anniversaries 必须是数组' } } if (!data.persons.every(_validatePerson)) { return { success: false, error: '人员数据格式不正确' } } if (!data.anniversaries.every(_validateAnniversary)) { return { success: false, error: '纪念日数据格式不正确' } } wx.setStorageSync('persons', data.persons) wx.setStorageSync('anniversaries', data.anniversaries) _cache.persons = data.persons _cache.anniversaries = data.anniversaries return { success: true } } catch (e) { console.error('导入数据失败', e) return { success: false, error: e.message } } } /** * 仅当本地为空时,从后端拉取所有人员和纪念日落地到本地 * Why:换设备/重装时,云端是唯一真相源,需要把数据拉回来恢复 */ async function pullFromCloudIfEmpty() { const hasLocal = getPersons().length > 0 || getAnniversaries().length > 0 if (hasLocal) return false const openid = wx.getStorageSync('openid') if (!openid) return false try { const [personsRes, annivRes] = await Promise.all([ api.person('get'), api.anniversary('get') ]) if (personsRes && personsRes.success && Array.isArray(personsRes.data) && personsRes.data.length > 0) { wx.setStorageSync('persons', personsRes.data) _cache.persons = personsRes.data } if (annivRes && annivRes.success && Array.isArray(annivRes.data) && annivRes.data.length > 0) { wx.setStorageSync('anniversaries', annivRes.data) _cache.anniversaries = annivRes.data } return true } catch (e) { console.error('[pullFromCloud] 失败', e) return false } } /** * 清空所有数据 */ function clearAllData() { try { wx.clearStorageSync() _invalidate() return true } catch (e) { console.error('清空数据失败', e) return false } } module.exports = { // 人员相关 savePersons, getPersons, getPersonById, addPerson, ensurePerson, updatePerson, deletePerson, deletePersonWithAnniversaries, // 纪念日相关 saveAnniversaries, getAnniversaries, getAnniversariesByPersonId, addAnniversary, updateAnniversary, deleteAnniversary, // 工具函数 exportData, importData, clearAllData, pullFromCloudIfEmpty }