This commit is contained in:
oneao committed 2025-11-11 22:31:33 +08:00
1 parent 7971c527af
commit b8a6b15355
27 files changed
+480 -399

No files matched your search

@@ -1,15 +1,28 @@
import { ScrollView, Text, View } from 'react-native'
import { ScrollView, Text } from 'react-native'
import { AButton } from '@/components/common/ao'
import { useUserStore } from '@/store/user'
export default function Chat() {
const userStore = useUserStore()
return (
<ScrollView contentContainerStyle={{ padding: 16 }}>
{Array.from({ length: 50 }).map((_, i) => (
<Text key={i} style={{ marginBottom: 10, fontSize: 16 }}>
Chat message
{' '}
{i + 1}
</Text>
))}
<ScrollView contentContainerStyle={{ padding: 16, marginTop: 22 }}>
<AButton
onPress={() => {
userStore.setUserInfo({
...(userStore.userInfo as any),
token: `test-token-${Date.now()}`,
})
}}
>
测试
</AButton>
<Text style={{ marginTop: 12 }}>
当前 token:
{' '}
{userStore.userInfo?.token ?? '(无)'}
</Text>
</ScrollView>
)
}
@@ -1,14 +1,17 @@
import type { MoneyCategoryResult } from '@/request/api/money'
import type { MoneyCategory } from '@/types/money'
import { DeleteIcon } from 'lucide-react-native'
import { useEffect, useState } from 'react'
import { Pressable, Text, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { AInput } from '@/components/common/ao'
import SegmentedTabs from '@/components/common/ao/SegmentedTabs'
import {
Drawer,
DrawerBackdrop,
DrawerBody,
DrawerContent,
DrawerFooter,
DrawerHeader,
} from '@/components/ui/drawer'
import { Grid, GridItem } from '@/components/ui/grid'
@@ -20,6 +23,37 @@ interface AddMoneyDrawerProps {
onClose: () => void
}
interface KeydownItem {
key: string | number
content: React.ReactNode
}
const keys: KeydownItem[] = [
{ key: '1', content: <Text className="text-2xl">1</Text> },
{ key: '2', content: <Text className="text-2xl">2</Text> },
{ key: '3', content: <Text className="text-2xl">3</Text> },
{ key: 'del', content: <DeleteIcon strokeWidth={1} /> },
{ key: '4', content: <Text className="text-2xl">4</Text> },
{ key: '5', content: <Text className="text-2xl">5</Text> },
{ key: '6', content: <Text className="text-2xl">6</Text> },
{ key: '+', content: <Text className="text-2xl">+</Text> },
{ key: '7', content: <Text className="text-2xl">7</Text> },
{ key: '8', content: <Text className="text-2xl">8</Text> },
{ key: '9', content: <Text className="text-2xl">9</Text> },
{ key: '-', content: <Text className="text-2xl">-</Text> },
{ key: 'clear', content: (
<View className="w-full h-full flex items-center justify-center">
<Text className="text-2xl text-red-500">AC</Text>
</View>
) },
{ key: '0', content: <Text className="text-2xl">0</Text> },
{ key: '.', content: <Text>.</Text> },
{ key: '/', content: (
<View className="w-full h-full bg-amber-100 flex items-center justify-center">
<Text className="text-2xl">完成</Text>
</View>
) },
]
export default function AddMoneyDrawer({
isOpen,
onClose,
@@ -27,12 +61,18 @@ export default function AddMoneyDrawer({
const insets = useSafeAreaInsets()
const [selectedIndex, setSelectedIndex] = useState(0)
const [selectedCategoryId, setSelectedCategoryId] = useState<number | null>(null)
const [showKeydown, setShowKeydown] = useState(false)
const [categories, setCategories] = useState<MoneyCategoryResult>({
income: [],
expense: [],
})
function selectCategory(item: MoneyCategory) {
setSelectedCategoryId(item.id)
setShowKeydown(true)
}
useEffect(() => {
if (isOpen) {
const fetchCategories = async () => {
@@ -50,72 +90,139 @@ export default function AddMoneyDrawer({
}
}, [isOpen])
const handlePress = (key: string | number, idx: number) => {
console.log('点击了格子 key:', key, '索引:', idx)
}
return (
<Drawer
isOpen={isOpen}
size="full"
anchor="bottom"
onClose={onClose}
>
<DrawerBackdrop />
<DrawerContent style={{ padding: 0, paddingLeft: 16, paddingRight: 16 }}>
<DrawerHeader
className="flex items-center justify-between"
style={{ paddingTop: insets.top, margin: 0, padding: 0 }}
>
<View className="w-1" />
<SegmentedTabs
value={selectedIndex}
tabs={[{ label: '收入' }, { label: '支出' }]}
onChange={setSelectedIndex}
style={{ width: 180 }}
className="mx-auto"
/>
<Pressable onPress={onClose}>
<Text className="text-gray-500 font-medium">取消</Text>
</Pressable>
</DrawerHeader>
<>
<Drawer
isOpen={isOpen}
size="full"
anchor="bottom"
onClose={onClose}
>
<DrawerBackdrop />
<DrawerContent style={{ padding: 0, paddingLeft: 16, paddingRight: 16 }}>
<DrawerHeader
className="flex items-center justify-between"
style={{ paddingTop: insets.top + 8, margin: 0, padding: 0 }}
>
<View className="w-1" />
<SegmentedTabs
value={selectedIndex}
tabs={[{ label: '收入' }, { label: '支出' }]}
onChange={setSelectedIndex}
style={{ width: 180 }}
className="mx-auto"
/>
<Pressable onPress={onClose}>
<Text className="text-gray-500 font-medium">取消</Text>
</Pressable>
</DrawerHeader>
<DrawerBody>
<Grid className="gap-4" _extra={{ className: 'grid-cols-4' }}>
{(() => {
const list = selectedIndex === 0 ? categories.income : categories.expense
const items = list.map((item) => {
const isSelected = selectedCategoryId === item.id
return (
<GridItem key={item.id} _extra={{ className: 'col-span-1' }}>
<Pressable
className="flex flex-col items-center justify-center rounded"
onPress={() => setSelectedCategoryId(item.id)}
>
<View
className={`w-14 h-14 rounded-full flex items-center justify-center ${
isSelected ? 'bg-blue-600' : 'bg-gray-200'
}`}
<DrawerBody>
<Grid className="gap-4" _extra={{ className: 'grid-cols-4' }}>
{(() => {
const list = selectedIndex === 0 ? categories.income : categories.expense
const items = list.map((item) => {
const isSelected = selectedCategoryId === item.id
return (
<GridItem key={item.id} _extra={{ className: 'col-span-1' }}>
<Pressable
className="flex flex-col items-center justify-center rounded"
onPress={() => selectCategory(item)}
>
<MoneyCategoryIcon name={item.icon} size={28} />
</View>
<Text className="text-sm mt-1">
{item.name}
</Text>
</Pressable>
</GridItem>
)
})
<View
className={`w-14 h-14 rounded-full flex items-center justify-center ${
isSelected ? 'bg-blue-100' : 'bg-gray-100'
}`}
>
<MoneyCategoryIcon name={item.icon} size={28} />
</View>
<Text className="text-sm mt-1">
{item.name}
</Text>
</Pressable>
</GridItem>
)
})
const remainder = list.length % 4
if (remainder > 0) {
const emptyCount = 4 - remainder
for (let i = 0; i < emptyCount; i++) {
items.push(<GridItem key={`empty-${i}`} _extra={{ className: 'col-span-1' }} />)
const remainder = list.length % 4
if (remainder > 0) {
const emptyCount = 4 - remainder
for (let i = 0; i < emptyCount; i++) {
items.push(<GridItem key={`empty-${i}`} _extra={{ className: 'col-span-1' }} />)
}
}
}
return items
})()}
</Grid>
</DrawerBody>
</DrawerContent>
</Drawer>
return items
})()}
</Grid>
</DrawerBody>
</DrawerContent>
</Drawer>
<Drawer
isOpen={showKeydown}
size="md"
anchor="bottom"
>
<DrawerContent
style={{
padding: 0,
margin: 0,
borderTopWidth: 0,
elevation: 30,
backgroundColor: 'white',
height: 360,
}}
>
<View className="flex-1">
<View className="p-4">
<Text className="text-3xl text-blue-700 text-right">0.00</Text>
<AInput
value=""
placeholder="备注"
className="bg-[#f2f3f5] border-0 mt-2"
size="sm"
/>
</View>
<View className="flex-1">
<View className="flex flex-row flex-wrap h-full">
{keys.map((item, idx) => {
const isFirstCol = idx % 4 === 0
const isFirstRow = idx < 4
const isLastCol = (idx + 1) % 4 === 0
const isLastRow = idx >= 12
return (
<Pressable
key={item.key}
onPress={() => handlePress(item.key, idx)}
style={{
width: '25%',
height: '25%',
justifyContent: 'center',
alignItems: 'center',
borderTopWidth: isFirstRow ? 0.3 : 0,
borderLeftWidth: isFirstCol ? 0.3 : 0,
borderRightWidth: !isLastCol ? 0.3 : 0,
borderBottomWidth: !isLastRow ? 0.3 : 0,
borderColor: '#ddd',
}}
>
{item.content}
</Pressable>
)
})}
</View>
</View>
</View>
</DrawerContent>
</Drawer>
</>
)
}
@@ -1,5 +1,6 @@
import React from 'react'
import {
IconGongzi,
IconJiaotong,
IconLingshi,
IconRiyongpin,
@@ -13,18 +14,19 @@ const iconMap: Record<string, React.ElementType> = {
jiaotong: IconJiaotong,
lingshi: IconLingshi,
riyongpin: IconRiyongpin,
shouru: IconShouru,
shucai: IconShucai,
yule: IconYule,
zhichu: IconZhichu,
gongzi: IconGongzi,
}
const DefaultIcon = IconLingshi
const DefaultIncomeIcon = IconShouru
const DefaultExpenseIcon = IconZhichu
interface CategoryIconProps {
name?: string
size?: number
color?: string
type?: 0 | 1
}
/**
@@ -34,7 +36,10 @@ export default function MoneyCategoryIcon({
name,
size = 24,
color,
type = 1,
}: CategoryIconProps) {
const IconComponent = iconMap[name ?? ''] || DefaultIcon
const IconComponent
= iconMap[name ?? ''] || (type === 0 ? DefaultIncomeIcon : DefaultExpenseIcon)
return <IconComponent size={size} color={color} />
}
@@ -1,6 +1,6 @@
import { Pressable, Text, View } from 'react-native'
import Animated, { useAnimatedStyle, withSpring, withTiming } from 'react-native-reanimated'
import { IconQuxian1 } from '@/components/iconfont'
// import { IconQuxian1 } from '@/components/iconfont'
interface TabSelectorProps {
options: string[]
@@ -43,7 +43,7 @@ const TabSelector: React.FC<TabSelectorProps> = ({ options, selected, onSelect }
animatedStyle,
]}
>
<IconQuxian1 size={22} color="#7566f3" />
{/* <IconQuxian1 size={22} color="#7566f3" /> */}
</Animated.View>
</Pressable>
</View>