This commit is contained in:
oneao committed 2025-11-19 22:55:09 +08:00
1 parent 49285f1df2
commit 63b168affc
7 files changed
+284 -324

No files matched your search

@@ -7,14 +7,15 @@ import { queryMoneyCategoryApi } from '@/request/api/money/category'
interface MoneyCategoryStore {
categories: MoneyCategoryItem[]
// 通过 getter 动态计算
expense: MoneyCategoryItem[]
income: MoneyCategoryItem[]
setCategories: (categories: MoneyCategoryItem[]) => void
addCategory: (category: MoneyCategoryItem) => void
removeCategory: (id: number) => void
init: () => Promise<void>
getExpenseCategories: () => MoneyCategoryItem[]
getIncomeCategories: () => MoneyCategoryItem[]
getCategoryById: (id: number) => MoneyCategoryItem | null
}
export const useMoneyCategoryStore = create<MoneyCategoryStore>()(
@@ -22,34 +23,32 @@ export const useMoneyCategoryStore = create<MoneyCategoryStore>()(
(set, get) => ({
categories: [],
// getter 样式属性,通过 get() 动态计算
get expense() {
return get().categories.filter(c => c.type === 0)
},
get income() {
return get().categories.filter(c => c.type === 1)
},
setCategories: categories => set({ categories }),
addCategory: category =>
set(state => ({ categories: [...state.categories, category] })),
set({ categories: [...get().categories, category] }),
removeCategory: id =>
set(state => ({ categories: state.categories.filter(c => c.id !== id) })),
set({ categories: get().categories.filter(c => c.id !== id) }),
init: async () => {
try {
const res = await queryMoneyCategoryApi()
if (res.isSuccess) {
const categories = res.data || []
set({ categories })
set({ categories: res.data || [] })
}
}
catch (error) {
console.error('Failed to fetch categories:', error)
catch (e) {
console.error('Fetch category failed:', e)
}
},
getExpenseCategories: () => (get().categories || []).filter(c => c.type === 0),
getIncomeCategories: () => (get().categories || []).filter(c => c.type === 1),
getCategoryById: (id: number) => {
return get().categories.find(c => c.id === id) || null
},
}),
{
name: 'money-category-storage',
@@ -1,3 +1,172 @@
import type { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record'
import { create } from 'zustand'
import { MoneyCategoryItem } from '@/types/money/category'
import { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record'
import { deleteMoneyRecordApi } from '@/request/api/money/record'
import { add, sub } from '@/utils/math'
import { isInMonth } from '@/utils/time'
interface MoneyRecordStore {
records: MoneyRecordGroup[]
currentMonth: string
total_income: string
total_expense: string
setRecords: (records: MoneyRecordGroup[], total_expense: string, total_income: string, month: string) => void
setCurrentMonth: (month: string) => void
addMoneyRecord: (data: MoneyRecordItem) => void
updateMoneyRecord: (updated: MoneyRecordItem) => void
deleteMoneyRecord: (id: number) => void
getMoneyRecordById: (id: number) => MoneyRecordItem | null
}
export const useMoneyRecordStore = create<MoneyRecordStore>((set, get) => ({
records: [],
currentMonth: '',
total_income: '0.00',
total_expense: '0.00',
setRecords: (records, total_expense, total_income, month) => {
set({ records, currentMonth: month, total_income, total_expense })
},
setCurrentMonth: month => set({ currentMonth: month }),
addMoneyRecord: (data) => {
set((prev) => {
if (!isInMonth(data.record_time, prev.currentMonth))
return prev
const records = [...prev.records]
const groupIndex = records.findIndex(g => g.record_time === data.record_time)
const amount = data.amount
if (groupIndex !== -1) {
const group = { ...records[groupIndex], records: [data, ...records[groupIndex].records] }
if (data.category_type === 0)
group.expense = add(group.expense, amount)
if (data.category_type === 1)
group.income = add(group.income, amount)
records[groupIndex] = group
}
else {
const newGroup: MoneyRecordGroup = {
record_time: data.record_time,
records: [data],
expense: data.category_type === 0 ? amount : '0.00',
income: data.category_type === 1 ? amount : '0.00',
}
const insertIndex = records.findIndex(g => g.record_time < data.record_time)
if (insertIndex === -1)
records.push(newGroup)
else records.splice(insertIndex, 0, newGroup)
}
return {
...prev,
records,
total_expense: data.category_type === 0 ? add(prev.total_expense, amount) : prev.total_expense,
total_income: data.category_type === 1 ? add(prev.total_income, amount) : prev.total_income,
}
})
},
updateMoneyRecord: (updated) => {
set((prev) => {
const records = [...prev.records]
const oldGroupIndex = records.findIndex(g => g.records.some(r => r.id === updated.id))
if (oldGroupIndex === -1)
return prev
const oldGroup = { ...records[oldGroupIndex], records: [...records[oldGroupIndex].records] }
const oldRecordIndex = oldGroup.records.findIndex(r => r.id === updated.id)
const oldRecord = oldGroup.records[oldRecordIndex]
const oldAmount = oldRecord.amount
const newAmount = updated.amount
// 移除旧记录
oldGroup.records.splice(oldRecordIndex, 1)
let total_expense = prev.total_expense
let total_income = prev.total_income
if (oldRecord.category_type === 0)
total_expense = sub(total_expense, oldAmount)
if (oldRecord.category_type === 1)
total_income = sub(total_income, oldAmount)
if (oldGroup.records.length === 0)
records.splice(oldGroupIndex, 1)
else records[oldGroupIndex] = oldGroup
if (!isInMonth(updated.record_time, prev.currentMonth)) {
return { ...prev, records, total_expense, total_income }
}
// 添加到新分组
const newGroupIndex = records.findIndex(g => g.record_time === updated.record_time)
if (newGroupIndex !== -1) {
const group = { ...records[newGroupIndex], records: [updated, ...records[newGroupIndex].records] }
if (updated.category_type === 0)
group.expense = add(group.expense, newAmount)
if (updated.category_type === 1)
group.income = add(group.income, newAmount)
records[newGroupIndex] = group
}
else {
const newGroup: MoneyRecordGroup = {
record_time: updated.record_time,
records: [updated],
expense: updated.category_type === 0 ? newAmount : '0.00',
income: updated.category_type === 1 ? newAmount : '0.00',
}
const insertIndex = records.findIndex(g => g.record_time < updated.record_time)
if (insertIndex === -1)
records.push(newGroup)
else records.splice(insertIndex, 0, newGroup)
}
if (updated.category_type === 0)
total_expense = add(total_expense, newAmount)
if (updated.category_type === 1)
total_income = add(total_income, newAmount)
return { ...prev, records, total_expense, total_income }
})
},
deleteMoneyRecord: (id) => {
set((prev) => {
const records = prev.records.map(g => ({ ...g, records: [...g.records] }))
let total_expense = prev.total_expense
let total_income = prev.total_income
records.forEach((group) => {
const index = group.records.findIndex(r => r.id === id)
if (index !== -1) {
const record = group.records[index]
if (record.category_type === 0)
total_expense = sub(total_expense, record.amount)
if (record.category_type === 1)
total_income = sub(total_income, record.amount)
group.records.splice(index, 1)
}
})
const newRecords = records.filter(g => g.records.length > 0)
return { ...prev, records: newRecords, total_expense, total_income }
})
deleteMoneyRecordApi({ id }).catch(console.error)
},
getMoneyRecordById: (id: number) => {
const records = get().records
for (const group of records) {
const record = group.records.find(r => r.id === id)
if (record)
return record
}
return null
},
}))