This commit is contained in:
oneao committed 2025-11-16 22:24:32 +08:00
1 parent caed43a011
commit 18e9d94b77
8 files changed
+148 -33

No files matched your search

@@ -1,7 +1,7 @@
import type { MoneyCategoryItem, QueryMoneyCategoryResult } from '@/types/money/category'
import type { InsertMoneyRecordResult, MoneyRecordBase } from '@/types/money/record'
import type { MoneyRecordBase, MoneyRecordItem } from '@/types/money/record'
import Big from 'big.js'
import { useEffect, useMemo, useState } from 'react'
import { useMemo, useState } from 'react'
import { FlatList, Keyboard, Pressable, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { AInput, LucideIcon } from '@/components/common/ao'
@@ -10,11 +10,9 @@ import SegmentedTabs from '@/components/common/ao/SegmentedTabs'
import {
Drawer,
DrawerBackdrop,
DrawerBody,
DrawerContent,
DrawerHeader,
} from '@/components/ui/drawer'
import { Grid, GridItem } from '@/components/ui/grid'
import { useKeyboardHeight } from '@/hooks/useKeyboardHeight'
import { queryMoneyCategoryApi } from '@/request/api/money/category'
import { insertMoneyRecordApi } from '@/request/api/money/record'
@@ -25,7 +23,7 @@ import MoneyCategoryIcon from './MoneyCategoryIcon'
interface AddMoneyDrawerProps {
isOpen: boolean
onClose: () => void
onConfirm?: (result: InsertMoneyRecordResult) => void
onConfirm?: (result: MoneyRecordItem) => void
}
interface KeydownItem {
@@ -81,6 +79,8 @@ export default function AddMoneyDrawer({
income: [],
expense: [],
})
// 选中分类
const [selectedCategory, setSelectedCategory] = useState<MoneyCategoryItem | null>(null)
const keyboardHeight = useKeyboardHeight()
@@ -96,11 +96,8 @@ export default function AddMoneyDrawer({
const [moneyRecord, setMoneyRecord] = useState<MoneyRecordBase>(defaultMoneyRecord)
function selectCategory(item: MoneyCategoryItem) {
setMoneyRecord({
...moneyRecord,
category_id: item.id,
})
function handleSelectCategory(item: MoneyCategoryItem) {
setSelectedCategory(item)
setShowKeydown(true)
}
@@ -128,6 +125,8 @@ export default function AddMoneyDrawer({
setSelectedIndex(0)
// 关闭日期
setShowDatePicker(false)
// 清空选中类别
setSelectedCategory(null)
}
// 关闭整个drawer处理
@@ -315,36 +314,53 @@ export default function AddMoneyDrawer({
}
}
// 保存
// 保存
function saveRecord() {
if (moneyRecord.category_id === -1) {
if (selectedCategory === null) {
toast.show({
title: '请选择分类',
})
return
}
if (moneyRecord.amount === '0.00') {
toast.show({
title: '请输入金额',
})
return
}
// 去掉金额负号
const amount = moneyRecord.amount.replace(/^-+/, '')
insertMoneyRecordApi({
...moneyRecord,
}).then((res) => {
if (res.isSuccess) {
resetData()
onConfirm?.(res.data)
}
else {
toast.show({
title: res.message || '保存失败',
})
}
}).catch((err) => {
console.log(err)
amount,
category_id: selectedCategory.id,
})
.then((res) => {
if (res.isSuccess) {
resetData()
const result: MoneyRecordItem = {
...res.data,
category_name: selectedCategory.name,
category_icon: selectedCategory.icon,
category_type: selectedCategory.type,
}
onConfirm?.(result)
}
else {
toast.show({
title: res.message || '保存失败',
})
}
})
.catch((err) => {
console.log(err)
})
}
return (
@@ -418,11 +434,11 @@ export default function AddMoneyDrawer({
return <View style={{ flex: 1 / 4, margin: 4 }} />
}
const isSelected = moneyRecord.category_id === item.id
const isSelected = selectedCategory?.id === item.id
return (
<Pressable
style={{ flex: 1 / 4, margin: 4, alignItems: 'center' }}
onPress={() => selectCategory(item)}
onPress={() => handleSelectCategory(item)}
>
<View
style={{
@@ -1,12 +1,14 @@
import type { QueryMoneyRecordsResult } from '@/types/money/record'
import type { MoneyRecordGroup, MoneyRecordItem, QueryMoneyRecordsResult } from '@/types/money/record'
import Big from 'big.js'
import React, { useEffect, useState } from 'react'
import { ScrollView, Text, TouchableOpacity, View } from 'react-native'
import { Text, TouchableOpacity, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
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 { add, sub } from '@/utils/math'
import { getCurrentYearMonth } from '@/utils/time'
import { toast } from '@/utils/toast'
import AddMoneyDrawer from './components/AddDrawer'
@@ -47,6 +49,71 @@ export default function Money() {
})
}, [searchParams])
function handleAddMoneyRecord(data: MoneyRecordItem) {
const recordTime = data.record_time
setMoneyRecords((prev) => {
const next = structuredClone(prev)
// 查找分组
const group = next.records.find(g => g.record_time === recordTime)
// === 已存在分组 ===
if (group) {
// 插入到最前面
group.records.unshift(data)
// 更新分组 & 总计
if (data.category_type === 0) {
// 收入
group.income = add(group.income, data.amount)
next.total_income = add(next.total_income, data.amount)
}
else if (data.category_type === 1) {
// 支出
group.expense = add(group.expense, data.amount)
next.total_expense = add(next.total_expense, data.amount)
}
return next
}
// === 无分组,新建 ===
const income = data.category_type === 0 ? data.amount : '0'
const expense = data.category_type === 1 ? data.amount : '0'
const newGroup: MoneyRecordGroup = {
record_time: recordTime,
income,
expense,
records: [data],
}
// ---- 按日期(YYYY-MM-DD)倒序插入 ----
// 最新日期插入前面,比如:2025-01-05 > 2025-01-03
const index = next.records.findIndex(g => g.record_time < recordTime)
if (index === -1) {
// 所有日期都比它大 → 插入最后
next.records.push(newGroup)
}
else {
// 插入正确位置
next.records.splice(index, 0, newGroup)
}
// 更新总计
if (data.category_type === 0) {
next.total_income = add(next.total_income, data.amount)
}
else if (data.category_type === 1) {
next.total_expense = add(next.total_expense, data.amount)
}
return next
})
}
return (
<View
className="flex-1"
@@ -151,6 +218,7 @@ export default function Money() {
}}
onConfirm={(res) => {
setShowAddDrawer(false)
handleAddMoneyRecord(res)
}}
/>
@@ -1,6 +1,7 @@
import { router } from 'expo-router'
import { StyleSheet, Text, View } from 'react-native'
import { AButton, AInput } from '@/components/common/ao'
import { LucideIcon } from '@/components/common/ao/index'
import { useUserStore } from '@/store/user'
export default function User() {
@@ -44,13 +45,15 @@ export default function User() {
</View>
<AButton onPress={() => {
router.replace('/abc')
router.replace('/auth/login')
}}
>
跳转到登陆页面
</AButton>
<AInput value="2" />
<LucideIcon icon="User" size={32} strokeWidth={1} />
</View>
)
}
@@ -24,7 +24,6 @@ export interface MoneyRecordItem extends MoneyRecordBase {
}
// 分组 & 查询结果
export interface MoneyRecordGroup {
record_time: string
expense: string
@@ -0,0 +1,32 @@
// utils/math.ts
import Big from 'big.js'
/**
* 加法
* @param a string number
* @param b string number
* @returns string number
*/
export function add(a: string | number, b: string | number): string {
try {
return new Big(a).plus(new Big(b)).toString()
}
catch {
return '0'
}
}
/**
* 减法
* @param a string number
* @param b string number
* @returns string number
*/
export function sub(a: string | number, b: string | number): string {
try {
return new Big(a).minus(new Big(b)).toString()
}
catch {
return '0'
}
}