u
This commit is contained in:
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'
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user