397 lines
12 KiB
JavaScript
397 lines
12 KiB
JavaScript
// API适配层,用于路由请求到在线API或本地数据库
|
||
|
||
import { db, createOfflineUser } from './db'
|
||
import * as onlineAuthApi from '../api/auth'
|
||
import * as onlineBillApi from '../api/bill'
|
||
import * as onlineCategoryApi from '../api/category'
|
||
import * as onlineAccountApi from '../api/account'
|
||
import * as onlineBudgetApi from '../api/budget'
|
||
import * as onlineOcrApi from '../api/ocr'
|
||
|
||
// 检查用户是否为离线用户
|
||
function isOfflineUser() {
|
||
const userInfo = uni.getStorageSync('userInfo') || {}
|
||
return userInfo.isOffline === true || userInfo.userId === 'local_user'
|
||
}
|
||
|
||
// 获取当前用户ID
|
||
function getCurrentUserId() {
|
||
const userInfo = uni.getStorageSync('userInfo') || {}
|
||
return userInfo.userId || 'local_user'
|
||
}
|
||
|
||
// API适配层实现
|
||
const apiAdapter = {
|
||
// 认证相关API
|
||
auth: {
|
||
// 登录
|
||
login: async (data) => {
|
||
return onlineAuthApi.login(data)
|
||
},
|
||
|
||
// 注册
|
||
register: async (data) => {
|
||
return onlineAuthApi.register(data)
|
||
},
|
||
|
||
// 离线登录
|
||
offlineLogin: async () => {
|
||
try {
|
||
// 创建或获取离线用户
|
||
const userId = await createOfflineUser()
|
||
|
||
// 设置用户信息
|
||
const userInfo = {
|
||
userId,
|
||
username: '离线用户',
|
||
nickname: '离线用户',
|
||
isOffline: true
|
||
}
|
||
|
||
// 保存到本地存储
|
||
uni.setStorageSync('userInfo', userInfo)
|
||
uni.setStorageSync('token', 'offline_token')
|
||
|
||
return {
|
||
token: 'offline_token',
|
||
username: '离线用户',
|
||
nickname: '离线用户',
|
||
userId
|
||
}
|
||
} catch (error) {
|
||
console.error('离线登录失败:', error)
|
||
throw error
|
||
}
|
||
}
|
||
},
|
||
|
||
// 账单相关API
|
||
bill: {
|
||
// 获取账单列表
|
||
getBills: async (params) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:从本地数据库获取
|
||
const userId = getCurrentUserId()
|
||
const sql = `SELECT * FROM bill WHERE user_id = ? ORDER BY bill_date DESC`
|
||
return db.query(sql, [userId])
|
||
} else {
|
||
// 在线模式:从服务器获取
|
||
return onlineBillApi.getBills(params)
|
||
}
|
||
},
|
||
|
||
// 创建账单
|
||
createBill: async (data) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:保存到本地数据库
|
||
const userId = getCurrentUserId()
|
||
const sql = `INSERT INTO bill (user_id, category_id, amount, description, bill_date, type)
|
||
VALUES (?, ?, ?, ?, ?, ?)`
|
||
const result = await db.update(sql, [
|
||
userId,
|
||
data.categoryId,
|
||
data.amount,
|
||
data.description || '',
|
||
data.billDate,
|
||
data.type
|
||
])
|
||
return { success: true, affectedRows: result }
|
||
} else {
|
||
// 在线模式:保存到服务器
|
||
return onlineBillApi.createBill(data)
|
||
}
|
||
},
|
||
|
||
// 更新账单
|
||
updateBill: async (id, data) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:更新本地数据库
|
||
const sql = `UPDATE bill SET category_id = ?, amount = ?, description = ?, bill_date = ?, type = ?, is_synced = 0
|
||
WHERE id = ?`
|
||
const result = await db.update(sql, [
|
||
data.categoryId,
|
||
data.amount,
|
||
data.description || '',
|
||
data.billDate,
|
||
data.type,
|
||
id
|
||
])
|
||
return { success: true, affectedRows: result }
|
||
} else {
|
||
// 在线模式:更新服务器
|
||
return onlineBillApi.updateBill(id, data)
|
||
}
|
||
},
|
||
|
||
// 删除账单
|
||
deleteBill: async (id) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:从本地数据库删除
|
||
const sql = `DELETE FROM bill WHERE id = ?`
|
||
const result = await db.update(sql, [id])
|
||
return { success: true, affectedRows: result }
|
||
} else {
|
||
// 在线模式:从服务器删除
|
||
return onlineBillApi.deleteBill(id)
|
||
}
|
||
}
|
||
},
|
||
|
||
// 分类相关API
|
||
category: {
|
||
// 获取分类列表
|
||
getCategories: async (params) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:从本地数据库获取
|
||
const userId = getCurrentUserId()
|
||
const type = params.type || ''
|
||
let sql = `SELECT * FROM category WHERE user_id IS NULL OR user_id = ?`
|
||
const sqlParams = [userId]
|
||
|
||
if (type) {
|
||
sql += ` AND type = ?`
|
||
sqlParams.push(type)
|
||
}
|
||
|
||
sql += ` ORDER BY type, sort_order ASC`
|
||
return db.query(sql, sqlParams)
|
||
} else {
|
||
// 在线模式:从服务器获取
|
||
return onlineCategoryApi.getCategories(params)
|
||
}
|
||
},
|
||
|
||
// 创建分类
|
||
createCategory: async (data) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:保存到本地数据库
|
||
const userId = getCurrentUserId()
|
||
const sql = `INSERT INTO category (user_id, name, icon, type, sort_order)
|
||
VALUES (?, ?, ?, ?, ?)`
|
||
const result = await db.update(sql, [
|
||
userId,
|
||
data.name,
|
||
data.icon || '📦',
|
||
data.type,
|
||
data.sortOrder || 0
|
||
])
|
||
return { success: true, affectedRows: result }
|
||
} else {
|
||
// 在线模式:保存到服务器
|
||
return onlineCategoryApi.createCategory(data)
|
||
}
|
||
},
|
||
|
||
// 更新分类
|
||
updateCategory: async (id, data) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:更新本地数据库
|
||
const sql = `UPDATE category SET name = ?, icon = ?, type = ?, sort_order = ?
|
||
WHERE id = ?`
|
||
const result = await db.update(sql, [
|
||
data.name,
|
||
data.icon,
|
||
data.type,
|
||
data.sortOrder || 0,
|
||
id
|
||
])
|
||
return { success: true, affectedRows: result }
|
||
} else {
|
||
// 在线模式:更新服务器
|
||
return onlineCategoryApi.updateCategory(id, data)
|
||
}
|
||
},
|
||
|
||
// 删除分类
|
||
deleteCategory: async (id) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:从本地数据库删除
|
||
const sql = `DELETE FROM category WHERE id = ? AND user_id = ?`
|
||
const result = await db.update(sql, [id, getCurrentUserId()])
|
||
return { success: true, affectedRows: result }
|
||
} else {
|
||
// 在线模式:从服务器删除
|
||
return onlineCategoryApi.deleteCategory(id)
|
||
}
|
||
}
|
||
},
|
||
|
||
// 账户相关API
|
||
account: {
|
||
// 获取账户信息
|
||
getAccount: async (params) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:从本地数据库获取
|
||
const userId = getCurrentUserId()
|
||
const sql = `SELECT * FROM account WHERE user_id = ?`
|
||
const accounts = await db.query(sql, [userId])
|
||
|
||
if (accounts.length > 0) {
|
||
// 获取收支统计
|
||
const incomeSql = `SELECT SUM(amount) as totalIncome FROM bill WHERE user_id = ? AND type = 2`
|
||
const expenseSql = `SELECT SUM(amount) as totalExpense FROM bill WHERE user_id = ? AND type = 1`
|
||
|
||
const incomeResult = await db.query(incomeSql, [userId])
|
||
const expenseResult = await db.query(expenseSql, [userId])
|
||
|
||
const totalIncome = incomeResult[0].totalIncome || 0
|
||
const totalExpense = expenseResult[0].totalExpense || 0
|
||
const initialBalance = accounts[0].initial_balance || 0
|
||
const balance = initialBalance + totalIncome - totalExpense
|
||
|
||
return {
|
||
...accounts[0],
|
||
totalIncome,
|
||
totalExpense,
|
||
balance
|
||
}
|
||
}
|
||
|
||
return null
|
||
} else {
|
||
// 在线模式:从服务器获取
|
||
return onlineAccountApi.getAccount(params)
|
||
}
|
||
},
|
||
|
||
// 更新账户信息
|
||
updateAccount: async (data) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:更新本地数据库
|
||
const userId = getCurrentUserId()
|
||
const sql = `UPDATE account SET name = ?, initial_balance = ? WHERE user_id = ?`
|
||
const result = await db.update(sql, [
|
||
data.name,
|
||
data.initialBalance || 0,
|
||
userId
|
||
])
|
||
|
||
// 返回更新后的账户信息
|
||
return apiAdapter.account.getAccount()
|
||
} else {
|
||
// 在线模式:更新服务器
|
||
return onlineAccountApi.updateAccount(data)
|
||
}
|
||
}
|
||
},
|
||
|
||
// 预算相关API
|
||
budget: {
|
||
// 获取预算信息
|
||
getBudget: async (params) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:从本地数据库获取
|
||
const userId = getCurrentUserId()
|
||
const now = new Date()
|
||
const year = params.year || now.getFullYear()
|
||
const month = params.month || (now.getMonth() + 1)
|
||
|
||
const sql = `SELECT * FROM budget WHERE user_id = ? AND year = ? AND month = ?`
|
||
const budgets = await db.query(sql, [userId, year, month])
|
||
|
||
if (budgets.length > 0) {
|
||
return budgets[0]
|
||
}
|
||
|
||
return {
|
||
userId,
|
||
year,
|
||
month,
|
||
amount: 0.00
|
||
}
|
||
} else {
|
||
// 在线模式:从服务器获取
|
||
return onlineBudgetApi.getBudget(params)
|
||
}
|
||
},
|
||
|
||
// 设置预算
|
||
setBudget: async (data) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:保存到本地数据库
|
||
const userId = getCurrentUserId()
|
||
const year = data.year
|
||
const month = data.month
|
||
const amount = data.amount || 0
|
||
|
||
// 检查是否已存在该月份预算
|
||
const checkSql = `SELECT * FROM budget WHERE user_id = ? AND year = ? AND month = ?`
|
||
const budgets = await db.query(checkSql, [userId, year, month])
|
||
|
||
let result
|
||
if (budgets.length > 0) {
|
||
// 更新现有预算
|
||
const sql = `UPDATE budget SET amount = ? WHERE user_id = ? AND year = ? AND month = ?`
|
||
result = await db.update(sql, [amount, userId, year, month])
|
||
} else {
|
||
// 创建新预算
|
||
const sql = `INSERT INTO budget (user_id, year, month, amount) VALUES (?, ?, ?, ?)`
|
||
result = await db.update(sql, [userId, year, month, amount])
|
||
}
|
||
|
||
return { success: true, affectedRows: result }
|
||
} else {
|
||
// 在线模式:保存到服务器
|
||
return onlineBudgetApi.setBudget(data)
|
||
}
|
||
},
|
||
|
||
// 获取预算结算信息
|
||
getBudgetSettlement: async (params) => {
|
||
if (isOfflineUser()) {
|
||
// 离线模式:从本地数据库计算
|
||
const userId = getCurrentUserId()
|
||
const now = new Date()
|
||
let year = now.getFullYear()
|
||
let month = now.getMonth()
|
||
|
||
// 如果当前是1月,上月是去年12月
|
||
if (month === 0) {
|
||
year--
|
||
month = 12
|
||
}
|
||
|
||
// 获取上月预算
|
||
const budgetSql = `SELECT * FROM budget WHERE user_id = ? AND year = ? AND month = ?`
|
||
const budgets = await db.query(budgetSql, [userId, year, month])
|
||
const budgetAmount = budgets[0]?.amount || 0
|
||
|
||
// 计算上月总支出
|
||
const expenseSql = `SELECT SUM(amount) as totalExpense FROM bill
|
||
WHERE user_id = ? AND type = 1
|
||
AND bill_date BETWEEN ? AND ?`
|
||
const startDate = `${year}-${month.toString().padStart(2, '0')}-01`
|
||
const endDate = new Date(year, month, 0).toISOString().split('T')[0]
|
||
|
||
const expenseResult = await db.query(expenseSql, [userId, startDate, endDate])
|
||
const totalExpense = expenseResult[0].totalExpense || 0
|
||
|
||
return {
|
||
year,
|
||
month,
|
||
budgetAmount,
|
||
totalExpense,
|
||
remainingAmount: budgetAmount - totalExpense
|
||
}
|
||
} else {
|
||
// 在线模式:从服务器获取
|
||
return onlineBudgetApi.getBudgetSettlement(params)
|
||
}
|
||
}
|
||
},
|
||
|
||
// OCR相关API
|
||
ocr: {
|
||
// 识别图片
|
||
recognizeImage: async (filePath) => {
|
||
// OCR功能仅在线用户可用
|
||
if (isOfflineUser()) {
|
||
throw new Error('OCR功能仅在线用户可用')
|
||
}
|
||
return onlineOcrApi.recognizeImage(filePath)
|
||
}
|
||
}
|
||
}
|
||
|
||
export default apiAdapter
|