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