This commit is contained in:
oneao committed 2025-11-17 17:30:20 +08:00
1 parent 18e9d94b77
commit 1f82f1dd1f
16 files changed
+1048 -297

No files matched your search

@@ -1,5 +1,4 @@
import type { MoneyRecordGroup, MoneyRecordItem, QueryMoneyRecordsResult } from '@/types/money/record'
import Big from 'big.js'
import React, { useEffect, useState } from 'react'
import { Text, TouchableOpacity, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
@@ -7,9 +6,9 @@ import { ADatePicker, LucideIcon } from '@/components/common/ao'
import { Fab, FabIcon } from '@/components/ui/fab'
import { AddIcon } from '@/components/ui/icon'
import { Progress, ProgressFilledTrack } from '@/components/ui/progress'
import { queryMoneyRecordsApi } from '@/request/api/money/record'
import { deleteMoneyRecordApi, queryMoneyRecordsApi } from '@/request/api/money/record'
import { add, sub } from '@/utils/math'
import { getCurrentYearMonth } from '@/utils/time'
import { getCurrentYearMonth, isInMonth } from '@/utils/time'
import { toast } from '@/utils/toast'
import AddMoneyDrawer from './components/AddDrawer'
import TransactionsList from './components/TransactionsList'
@@ -30,6 +29,8 @@ export default function Money() {
total_income: '0',
records: [],
})
// 更新
const [updateItem, setUpdateItem] = useState<MoneyRecordItem | null>(null)
useEffect(() => {
queryMoneyRecordsApi({
@@ -53,6 +54,11 @@ export default function Money() {
const recordTime = data.record_time
setMoneyRecords((prev) => {
// 不在当前月份 → 不添加,直接返回
if (!isInMonth(recordTime, searchParams.record_time)) {
return prev
}
const next = structuredClone(prev)
// 查找分组
@@ -64,12 +70,12 @@ export default function Money() {
group.records.unshift(data)
// 更新分组 & 总计
if (data.category_type === 0) {
if (data.category_type === 1) {
// 收入
group.income = add(group.income, data.amount)
next.total_income = add(next.total_income, data.amount)
}
else if (data.category_type === 1) {
else if (data.category_type === 0) {
// 支出
group.expense = add(group.expense, data.amount)
next.total_expense = add(next.total_expense, data.amount)
@@ -79,8 +85,8 @@ export default function Money() {
}
// === 无分组,新建 ===
const income = data.category_type === 0 ? data.amount : '0'
const expense = data.category_type === 1 ? data.amount : '0'
const expense = data.category_type === 0 ? data.amount : '0'
const income = data.category_type === 1 ? data.amount : '0'
const newGroup: MoneyRecordGroup = {
record_time: recordTime,
@@ -94,11 +100,9 @@ export default function Money() {
const index = next.records.findIndex(g => g.record_time < recordTime)
if (index === -1) {
// 所有日期都比它大 → 插入最后
next.records.push(newGroup)
}
else {
// 插入正确位置
next.records.splice(index, 0, newGroup)
}
@@ -114,6 +118,164 @@ export default function Money() {
})
}
function handleUpdateMoneyRecord(updated: MoneyRecordItem) {
setMoneyRecords((prev) => {
const next = structuredClone(prev)
// 找到旧记录
const oldGroupIndex = next.records.findIndex(g =>
g.records.some(r => r.id === updated.id),
)
if (oldGroupIndex === -1)
return next
const oldGroup = next.records[oldGroupIndex]
const oldRecordIndex = oldGroup.records.findIndex(r => r.id === updated.id)
const oldRecord = oldGroup.records[oldRecordIndex]
const oldAmount = oldRecord.amount
const newAmount = updated.amount
const oldType = oldRecord.category_type
const newType = updated.category_type
const oldDate = oldRecord.record_time
const newDate = updated.record_time
// record_time 没变 → 同分组更新
if (oldDate === newDate) {
oldGroup.records[oldRecordIndex] = updated
// 调整分组金额
if (oldType === 1)
oldGroup.income = sub(oldGroup.income, oldAmount)
if (oldType === 0)
oldGroup.expense = sub(oldGroup.expense, oldAmount)
if (newType === 1)
oldGroup.income = add(oldGroup.income, newAmount)
if (newType === 0)
oldGroup.expense = add(oldGroup.expense, newAmount)
// 调整总计
if (oldType === 1)
next.total_income = sub(next.total_income, oldAmount)
if (oldType === 0)
next.total_expense = sub(next.total_expense, oldAmount)
if (newType === 1)
next.total_income = add(next.total_income, newAmount)
if (newType === 0)
next.total_expense = add(next.total_expense, newAmount)
return next
}
// -------------------------
// 判断是否在当前月份内
// -------------------------
const currentMonth = searchParams.record_time // 例如 "2025-01"
const isInCurrentMonth = isInMonth(newDate, currentMonth)
// 1. 先移除旧分组 & 调整金额(无论是否在当前月份,都要做)
if (oldType === 1)
oldGroup.income = sub(oldGroup.income, oldAmount)
if (oldType === 0)
oldGroup.expense = sub(oldGroup.expense, oldAmount)
if (oldType === 1)
next.total_income = sub(next.total_income, oldAmount)
if (oldType === 0)
next.total_expense = sub(next.total_expense, oldAmount)
oldGroup.records.splice(oldRecordIndex, 1)
if (oldGroup.records.length === 0) {
next.records.splice(oldGroupIndex, 1)
}
// -------------------------
// 不在当前月份 → 不显示,直接返回 next
// -------------------------
if (!isInCurrentMonth) {
return next
}
// -------------------------
// 在当前月份 → 移动到新分组
// -------------------------
// 找新分组,如果没有就创建
let newGroup = next.records.find(g => g.record_time === newDate)
if (!newGroup) {
newGroup = {
record_time: newDate,
income: '0.00',
expense: '0.00',
records: [],
}
// 按日期倒序插入
const insertIndex = next.records.findIndex(g => g.record_time < newDate)
if (insertIndex === -1)
next.records.push(newGroup)
else
next.records.splice(insertIndex, 0, newGroup)
}
// 添加到新分组
newGroup.records.unshift(updated)
// 加金额
if (newType === 1)
newGroup.income = add(newGroup.income, newAmount)
if (newType === 0)
newGroup.expense = add(newGroup.expense, newAmount)
if (newType === 1)
next.total_income = add(next.total_income, newAmount)
if (newType === 0)
next.total_expense = add(next.total_expense, newAmount)
return next
})
}
function handleDeleteRecord(id: number) {
// 直接更新本地状态
setMoneyRecords((prev) => {
const next = structuredClone(prev)
// 遍历每个分组
next.records.forEach((group) => {
const index = group.records.findIndex(r => r.id === id)
if (index !== -1) {
const record = group.records[index]
// 更新分组金额
if (record.category_type === 1) {
group.income = sub(group.income, record.amount)
next.total_income = sub(next.total_income, record.amount)
}
else if (record.category_type === 0) {
group.expense = sub(group.expense, record.amount)
next.total_expense = sub(next.total_expense, record.amount)
}
// 删除记录
group.records.splice(index, 1)
}
})
// 删除空分组
next.records = next.records.filter(g => g.records.length > 0)
return next
})
// 异步请求删除 API
deleteMoneyRecordApi({ id }).catch((err) => {
console.log(err)
})
}
return (
<View
className="flex-1"
@@ -122,7 +284,7 @@ export default function Money() {
}}
>
<View>
<View className="flex flex-row justify-between items-center px-4">
<View className="flex flex-row justify-between items-center px-3">
<TouchableOpacity
onPress={() => setShowDatePicker(true)}
className="flex flex-row items-center gap-1"
@@ -198,8 +360,17 @@ export default function Money() {
</View>
</View>
<View className="flex-1 px-4 mt-2">
<TransactionsList records={moneyRecords.records} />
<View className="flex-1 mt-2">
<TransactionsList
records={moneyRecords.records}
onUpdate={(data) => {
setUpdateItem(data)
setShowAddDrawer(true)
}}
onDelete={(id) => {
handleDeleteRecord(id)
}}
/>
</View>
<Fab
@@ -213,12 +384,20 @@ export default function Money() {
<AddMoneyDrawer
isOpen={showAddDrawer}
updateData={updateItem}
onClose={() => {
setShowAddDrawer(false)
setUpdateItem(null)
}}
onConfirm={(res) => {
setShowAddDrawer(false)
handleAddMoneyRecord(res)
if (updateItem !== null) {
setUpdateItem(null)
handleUpdateMoneyRecord(res)
}
else {
handleAddMoneyRecord(res)
}
}}
/>