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 } }