第一次上传
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
import { reactive } from 'vue'
|
||||
import { createDefaultData } from './constants'
|
||||
|
||||
const STORAGE_KEY = 'bill-helper-miniapp-v1'
|
||||
|
||||
function deepClone(value) {
|
||||
return JSON.parse(JSON.stringify(value))
|
||||
}
|
||||
|
||||
function normalizeData(raw) {
|
||||
const fallback = createDefaultData()
|
||||
const source = raw || {}
|
||||
|
||||
return {
|
||||
categories: {
|
||||
expense: Array.isArray(source.categories?.expense) && source.categories.expense.length
|
||||
? source.categories.expense
|
||||
: fallback.categories.expense,
|
||||
income: Array.isArray(source.categories?.income) && source.categories.income.length
|
||||
? source.categories.income
|
||||
: fallback.categories.income
|
||||
},
|
||||
accounts: Array.isArray(source.accounts) && source.accounts.length ? source.accounts : fallback.accounts,
|
||||
bills: Array.isArray(source.bills) ? source.bills : fallback.bills,
|
||||
budgets: {
|
||||
total: Number(source.budgets?.total) || fallback.budgets.total,
|
||||
categoryBudgets: source.budgets?.categoryBudgets || fallback.budgets.categoryBudgets
|
||||
},
|
||||
settings: {
|
||||
theme: source.settings?.theme || fallback.settings.theme,
|
||||
profile: {
|
||||
authorized: Boolean(source.settings?.profile?.authorized),
|
||||
nickname: source.settings?.profile?.nickname || fallback.settings.profile.nickname,
|
||||
avatarUrl: source.settings?.profile?.avatarUrl || ''
|
||||
},
|
||||
lastBackupAt: source.settings?.lastBackupAt || ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadData() {
|
||||
try {
|
||||
const raw = uni.getStorageSync(STORAGE_KEY)
|
||||
if (!raw) {
|
||||
const seeded = createDefaultData()
|
||||
uni.setStorageSync(STORAGE_KEY, seeded)
|
||||
return seeded
|
||||
}
|
||||
return normalizeData(raw)
|
||||
} catch (error) {
|
||||
return createDefaultData()
|
||||
}
|
||||
}
|
||||
|
||||
const state = reactive(normalizeData(loadData()))
|
||||
|
||||
function patchState(nextState) {
|
||||
state.categories.expense.splice(0, state.categories.expense.length, ...nextState.categories.expense)
|
||||
state.categories.income.splice(0, state.categories.income.length, ...nextState.categories.income)
|
||||
state.accounts.splice(0, state.accounts.length, ...nextState.accounts)
|
||||
state.bills.splice(0, state.bills.length, ...nextState.bills)
|
||||
state.budgets.total = Number(nextState.budgets.total) || 0
|
||||
state.budgets.categoryBudgets = { ...nextState.budgets.categoryBudgets }
|
||||
state.settings.theme = nextState.settings.theme
|
||||
state.settings.profile = { ...nextState.settings.profile }
|
||||
state.settings.lastBackupAt = nextState.settings.lastBackupAt || ''
|
||||
}
|
||||
|
||||
function persist() {
|
||||
uni.setStorageSync(STORAGE_KEY, deepClone(state))
|
||||
}
|
||||
|
||||
function buildBillPayload(payload) {
|
||||
return {
|
||||
id: payload.id || `bill-${Date.now()}`,
|
||||
type: payload.type || 'expense',
|
||||
amount: Number(payload.amount) || 0,
|
||||
categoryId: payload.categoryId || '',
|
||||
accountId: payload.accountId || '',
|
||||
note: payload.note || '',
|
||||
date: payload.date,
|
||||
createdAt: payload.createdAt || Date.now()
|
||||
}
|
||||
}
|
||||
|
||||
export function useAppStore() {
|
||||
function saveBill(payload) {
|
||||
const nextBill = buildBillPayload(payload)
|
||||
const index = state.bills.findIndex((item) => item.id === nextBill.id)
|
||||
|
||||
if (index === -1) {
|
||||
state.bills.unshift(nextBill)
|
||||
} else {
|
||||
state.bills.splice(index, 1, nextBill)
|
||||
}
|
||||
|
||||
persist()
|
||||
}
|
||||
|
||||
function deleteBill(id) {
|
||||
state.bills.splice(
|
||||
0,
|
||||
state.bills.length,
|
||||
...state.bills.filter((item) => item.id !== id)
|
||||
)
|
||||
persist()
|
||||
}
|
||||
|
||||
function deleteBills(ids) {
|
||||
const idSet = new Set(ids)
|
||||
state.bills.splice(
|
||||
0,
|
||||
state.bills.length,
|
||||
...state.bills.filter((item) => !idSet.has(item.id))
|
||||
)
|
||||
persist()
|
||||
}
|
||||
|
||||
function setBudgetTotal(value) {
|
||||
state.budgets.total = Number(value) || 0
|
||||
persist()
|
||||
}
|
||||
|
||||
function setCategoryBudget(categoryId, value) {
|
||||
state.budgets.categoryBudgets = {
|
||||
...state.budgets.categoryBudgets,
|
||||
[categoryId]: Number(value) || 0
|
||||
}
|
||||
persist()
|
||||
}
|
||||
|
||||
function setTheme(theme) {
|
||||
state.settings.theme = theme
|
||||
persist()
|
||||
}
|
||||
|
||||
function setProfile(profile) {
|
||||
state.settings.profile = {
|
||||
...state.settings.profile,
|
||||
...profile
|
||||
}
|
||||
persist()
|
||||
}
|
||||
|
||||
function markBackup(timeLabel) {
|
||||
state.settings.lastBackupAt = timeLabel
|
||||
persist()
|
||||
}
|
||||
|
||||
function exportBackup() {
|
||||
return JSON.stringify(deepClone(state), null, 2)
|
||||
}
|
||||
|
||||
function importBackup(payload) {
|
||||
const parsed = normalizeData(JSON.parse(payload))
|
||||
patchState(parsed)
|
||||
persist()
|
||||
}
|
||||
|
||||
function resetAll() {
|
||||
patchState(createDefaultData())
|
||||
persist()
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
saveBill,
|
||||
deleteBill,
|
||||
deleteBills,
|
||||
setBudgetTotal,
|
||||
setCategoryBudget,
|
||||
setTheme,
|
||||
setProfile,
|
||||
markBackup,
|
||||
exportBackup,
|
||||
importBackup,
|
||||
resetAll
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user