374 lines
11 KiB
JavaScript
374 lines
11 KiB
JavaScript
// 数据同步功能实现
|
|
|
|
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
|