// 数据同步功能实现 import { db } from './db' import * as onlineBillApi from '../api/bill' import * as onlineCategoryApi from '../api/category' import * as onlineAccountApi from '../api/account' import * as onlineBudgetApi from '../api/budget' // 获取当前用户ID function getCurrentUserId() { const userInfo = uni.getStorageSync('userInfo') || {} return userInfo.userId || 'local_user' } // 检查是否为离线用户 function isOfflineUser() { const userInfo = uni.getStorageSync('userInfo') || {} return userInfo.isOffline === true || userInfo.userId === 'local_user' } // 账单同步逻辑 const syncBills = async () => { if (isOfflineUser()) { throw new Error('离线用户无法同步数据') } const userId = getCurrentUserId() try { // 1. 获取本地未同步的账单 const localBillsSql = `SELECT * FROM bill WHERE user_id = ? AND is_synced = 0` const localBills = await db.query(localBillsSql, [userId]) // 2. 获取服务器端账单 const serverBills = await onlineBillApi.getBills({ userId }) // 3. 比较并同步数据 for (const localBill of localBills) { // 检查服务器是否已有相同账单 const existingBill = serverBills.find(bill => { return bill.amount === localBill.amount && bill.type === localBill.type && bill.bill_date === localBill.bill_date && bill.description === localBill.description && bill.category_id === localBill.category_id }) if (existingBill) { // 已有相同账单,标记为已同步 const updateSql = `UPDATE bill SET is_synced = 1 WHERE id = ?` await db.update(updateSql, [localBill.id]) } else { // 没有相同账单,上传到服务器 await onlineBillApi.createBill({ categoryId: localBill.category_id, amount: localBill.amount, description: localBill.description, billDate: localBill.bill_date, type: localBill.type }) // 标记为已同步 const updateSql = `UPDATE bill SET is_synced = 1 WHERE id = ?` await db.update(updateSql, [localBill.id]) } } // 4. 将服务器端数据同步到本地 for (const serverBill of serverBills) { // 检查本地是否已有相同账单 const checkSql = `SELECT * FROM bill WHERE user_id = ? AND amount = ? AND type = ? AND bill_date = ? AND description = ? AND category_id = ?` const existingBills = await db.query(checkSql, [ userId, serverBill.amount, serverBill.type, serverBill.bill_date, serverBill.description, serverBill.category_id ]) if (existingBills.length === 0) { // 本地没有相同账单,添加到本地 const insertSql = `INSERT INTO bill (user_id, category_id, amount, description, bill_date, type, is_synced) VALUES (?, ?, ?, ?, ?, ?, 1)` await db.update(insertSql, [ userId, serverBill.category_id, serverBill.amount, serverBill.description, serverBill.bill_date, serverBill.type ]) } } return { success: true, message: '账单同步成功', syncedCount: localBills.length } } catch (error) { console.error('同步账单失败:', error) throw error } } // 分类同步逻辑 const syncCategories = async () => { if (isOfflineUser()) { throw new Error('离线用户无法同步数据') } const userId = getCurrentUserId() try { // 1. 获取本地用户自定义分类 const localCategoriesSql = `SELECT * FROM category WHERE user_id = ?` const localCategories = await db.query(localCategoriesSql, [userId]) // 2. 获取服务器端分类 const serverCategories = await onlineCategoryApi.getCategories({ userId }) // 3. 比较并同步数据 for (const localCategory of localCategories) { // 检查服务器是否已有相同分类 const existingCategory = serverCategories.find(category => { return category.name === localCategory.name && category.type === localCategory.type }) if (!existingCategory) { // 没有相同分类,上传到服务器 await onlineCategoryApi.createCategory({ name: localCategory.name, icon: localCategory.icon, type: localCategory.type, sortOrder: localCategory.sort_order }) } } // 4. 将服务器端分类同步到本地 for (const serverCategory of serverCategories) { // 检查本地是否已有相同分类 const checkSql = `SELECT * FROM category WHERE user_id = ? AND name = ? AND type = ?` const existingCategories = await db.query(checkSql, [ userId, serverCategory.name, serverCategory.type ]) if (existingCategories.length === 0) { // 本地没有相同分类,添加到本地 const insertSql = `INSERT INTO category (user_id, name, icon, type, sort_order) VALUES (?, ?, ?, ?, ?)` await db.update(insertSql, [ userId, serverCategory.name, serverCategory.icon, serverCategory.type, serverCategory.sort_order ]) } } return { success: true, message: '分类同步成功' } } catch (error) { console.error('同步分类失败:', error) throw error } } // 账户同步逻辑 const syncAccount = async () => { if (isOfflineUser()) { throw new Error('离线用户无法同步数据') } const userId = getCurrentUserId() try { // 1. 获取本地账户信息 const localAccountSql = `SELECT * FROM account WHERE user_id = ?` const localAccounts = await db.query(localAccountSql, [userId]) if (localAccounts.length === 0) { return { success: true, message: '本地没有账户信息需要同步' } } const localAccount = localAccounts[0] // 2. 获取服务器端账户信息 const serverAccount = await onlineAccountApi.getAccount({ userId }) // 3. 比较并同步数据 if (serverAccount) { // 服务器有账户信息,比较并更新 if (localAccount.name !== serverAccount.name || localAccount.initial_balance !== serverAccount.initial_balance) { // 本地与服务器信息不一致,更新服务器端 await onlineAccountApi.updateAccount({ name: localAccount.name, initialBalance: localAccount.initial_balance }) } } else { // 服务器没有账户信息,创建新账户 await onlineAccountApi.updateAccount({ name: localAccount.name, initialBalance: localAccount.initial_balance }) } // 4. 将服务器端账户信息同步到本地 const updatedServerAccount = await onlineAccountApi.getAccount({ userId }) const updateSql = `UPDATE account SET name = ?, initial_balance = ? WHERE user_id = ?` await db.update(updateSql, [ updatedServerAccount.name, updatedServerAccount.initial_balance, userId ]) return { success: true, message: '账户同步成功' } } catch (error) { console.error('同步账户失败:', error) throw error } } // 预算同步逻辑 const syncBudgets = async () => { if (isOfflineUser()) { throw new Error('离线用户无法同步数据') } const userId = getCurrentUserId() try { // 1. 获取本地预算 const localBudgetsSql = `SELECT * FROM budget WHERE user_id = ?` const localBudgets = await db.query(localBudgetsSql, [userId]) // 2. 获取服务器端预算 const serverBudget = await onlineBudgetApi.getBudget({ userId }) // 3. 比较并同步数据 for (const localBudget of localBudgets) { // 检查服务器是否已有相同月份预算 const checkSql = `SELECT * FROM budget WHERE user_id = ? AND year = ? AND month = ?` const existingBudgets = await db.query(checkSql, [ userId, localBudget.year, localBudget.month ]) if (existingBudgets.length === 0) { // 没有相同月份预算,上传到服务器 await onlineBudgetApi.setBudget({ userId, year: localBudget.year, month: localBudget.month, amount: localBudget.amount }) } else if (existingBudgets[0].amount !== localBudget.amount) { // 预算金额不一致,更新服务器 await onlineBudgetApi.setBudget({ userId, year: localBudget.year, month: localBudget.month, amount: localBudget.amount }) } } // 4. 将服务器端预算同步到本地 if (serverBudget) { // 检查本地是否已有相同月份预算 const checkSql = `SELECT * FROM budget WHERE user_id = ? AND year = ? AND month = ?` const existingBudgets = await db.query(checkSql, [ userId, serverBudget.year, serverBudget.month ]) if (existingBudgets.length === 0) { // 本地没有相同月份预算,添加到本地 const insertSql = `INSERT INTO budget (user_id, year, month, amount, is_synced) VALUES (?, ?, ?, ?, 1)` await db.update(insertSql, [ userId, serverBudget.year, serverBudget.month, serverBudget.amount ]) } else if (existingBudgets[0].amount !== serverBudget.amount) { // 预算金额不一致,更新本地 const updateSql = `UPDATE budget SET amount = ?, is_synced = 1 WHERE user_id = ? AND year = ? AND month = ?` await db.update(updateSql, [ serverBudget.amount, userId, serverBudget.year, serverBudget.month ]) } } return { success: true, message: '预算同步成功' } } catch (error) { console.error('同步预算失败:', error) throw error } } // 全量同步数据 const syncAllData = async () => { if (isOfflineUser()) { throw new Error('离线用户无法同步数据') } try { // 1. 同步账单 const billResult = await syncBills() // 2. 同步分类 const categoryResult = await syncCategories() // 3. 同步账户 const accountResult = await syncAccount() // 4. 同步预算 const budgetResult = await syncBudgets() return { success: true, message: '数据同步成功', details: { bills: billResult, categories: categoryResult, account: accountResult, budgets: budgetResult } } } catch (error) { console.error('全量同步失败:', error) throw error } } // 数据同步模块导出 export const sync = { // 全量同步 syncAll: syncAllData, // 账单同步 syncBills, // 分类同步 syncCategories, // 账户同步 syncAccount, // 预算同步 syncBudgets, // 检查同步状态 checkSyncStatus: () => { const userInfo = uni.getStorageSync('userInfo') || {} const lastSyncTime = uni.getStorageSync('lastSyncTime') || null return { isOffline: userInfo.isOffline === true || userInfo.userId === 'local_user', lastSyncTime } } } export default sync