u
This commit is contained in:
1 parent
95d645f572
commit
68a834dd18
6 files changed
+331
-218
No files matched your search
@@ -1,19 +1,39 @@
|
||||
import type { DateType } from 'react-native-ui-datepicker'
|
||||
import { useState } from 'react'
|
||||
import DateTimePicker, { useDefaultStyles } from 'react-native-ui-datepicker'
|
||||
|
||||
export default function Calendar() {
|
||||
const defaultStyles = useDefaultStyles()
|
||||
const [selected, setSelected] = useState<DateType>()
|
||||
import React, { useState } from 'react'
|
||||
import { KeyboardAvoidingView, Platform, StyleSheet, View } from 'react-native'
|
||||
import { KeyboardProvider } from 'react-native-keyboard-controller'
|
||||
import { AInput } from '@/components/common/ao'
|
||||
|
||||
export default function MyInput() {
|
||||
return (
|
||||
<DateTimePicker
|
||||
mode="single"
|
||||
date={selected}
|
||||
onChange={({ date }) => setSelected(date)}
|
||||
styles={defaultStyles}
|
||||
className="mt-22"
|
||||
/>
|
||||
<View style={styles.content}>
|
||||
<View style={styles.topSpace} />
|
||||
|
||||
{/* 输入框 */}
|
||||
<View style={styles.inputWrapper}>
|
||||
<AInput
|
||||
value=""
|
||||
placeholder="备注"
|
||||
className="bg-[#f2f3f5] border-0"
|
||||
size="sm"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
topSpace: {
|
||||
flex: 1,
|
||||
},
|
||||
inputWrapper: {
|
||||
marginHorizontal: 16,
|
||||
marginBottom: 20,
|
||||
},
|
||||
})
|
||||
@@ -2,8 +2,8 @@ import type { MoneyCategoryResult } from '@/request/api/money'
|
||||
import type { MoneyCategory } from '@/types/money'
|
||||
import Big from 'big.js'
|
||||
import dayjs from 'dayjs'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { Keyboard, Pressable, StyleSheet, Text, View } from 'react-native'
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import { AInput, LucideIcon } from '@/components/common/ao'
|
||||
import SegmentedTabs from '@/components/common/ao/SegmentedTabs'
|
||||
@@ -75,6 +75,44 @@ export default function AddMoneyDrawer({
|
||||
setSelectedCategoryId(item.id)
|
||||
setShowKeydown(true)
|
||||
}
|
||||
const categoryNames = [
|
||||
'餐饮',
|
||||
'交通',
|
||||
'娱乐',
|
||||
'购物',
|
||||
'工资',
|
||||
'投资',
|
||||
'住房',
|
||||
'医疗',
|
||||
'学习',
|
||||
'旅行',
|
||||
'通讯',
|
||||
'宠物',
|
||||
'礼物',
|
||||
'数码',
|
||||
'日用品',
|
||||
'保险',
|
||||
'孩子',
|
||||
'捐赠',
|
||||
'水电',
|
||||
'理发',
|
||||
]
|
||||
|
||||
function generateCategories(count: number, type: number): MoneyCategory[] {
|
||||
const result: MoneyCategory[] = []
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const name = categoryNames[Math.floor(Math.random() * categoryNames.length)]
|
||||
result.push({
|
||||
id: i,
|
||||
user_id: 1,
|
||||
name,
|
||||
icon: `icon_${name}`,
|
||||
sort_number: i,
|
||||
type,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
@@ -83,6 +121,10 @@ export default function AddMoneyDrawer({
|
||||
const res = await getMoneyCategoryApi()
|
||||
if (res.isSuccess) {
|
||||
// setCategories(res.data)
|
||||
setCategories({
|
||||
income: generateCategories(100, 1),
|
||||
expense: generateCategories(100, 2),
|
||||
})
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
@@ -241,92 +283,94 @@ export default function AddMoneyDrawer({
|
||||
return total.toFixed(2)
|
||||
}
|
||||
}
|
||||
const inputRef = useRef<any>(null)
|
||||
|
||||
const [isFocused, setIsFocused] = useState(false)
|
||||
|
||||
// 监听键盘收起
|
||||
useEffect(() => {
|
||||
const sub = Keyboard.addListener('keyboardDidHide', () => {
|
||||
if (inputRef.current) {
|
||||
inputRef.current.blur() // 收起键盘时失去焦点
|
||||
setIsFocused(false)
|
||||
}
|
||||
})
|
||||
return () => sub.remove()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Drawer
|
||||
isOpen={isOpen}
|
||||
size="full"
|
||||
anchor="bottom"
|
||||
onClose={onMainDrawerClose}
|
||||
>
|
||||
<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={onMainDrawerClose}>
|
||||
<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={() => selectCategory(item)}
|
||||
>
|
||||
<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' }} />)
|
||||
}
|
||||
}
|
||||
|
||||
return items
|
||||
})()}
|
||||
</Grid>
|
||||
</DrawerBody>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<Drawer
|
||||
isOpen={showKeydown}
|
||||
size="md"
|
||||
anchor="bottom"
|
||||
onClose={() => setShowKeydown(false)}
|
||||
>
|
||||
<DrawerContent
|
||||
style={{
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
borderTopWidth: 0,
|
||||
elevation: 30,
|
||||
backgroundColor: 'white',
|
||||
height: 360,
|
||||
}}
|
||||
<Drawer
|
||||
isOpen={isOpen}
|
||||
size="full"
|
||||
anchor="bottom"
|
||||
onClose={onMainDrawerClose}
|
||||
>
|
||||
<DrawerBackdrop />
|
||||
<DrawerContent style={{ padding: 0, flex: 1 }}>
|
||||
<DrawerHeader
|
||||
className="flex items-center justify-between"
|
||||
style={{ paddingTop: insets.top + 8, paddingLeft: 16, paddingRight: 16 }}
|
||||
>
|
||||
<View className="flex-1">
|
||||
<View className="w-1" />
|
||||
<SegmentedTabs
|
||||
value={selectedIndex}
|
||||
tabs={[{ label: '收入' }, { label: '支出' }]}
|
||||
onChange={setSelectedIndex}
|
||||
style={{ width: 180 }}
|
||||
className="mx-auto"
|
||||
/>
|
||||
<Pressable onPress={onMainDrawerClose}>
|
||||
<Text className="text-gray-500 font-medium">取消</Text>
|
||||
</Pressable>
|
||||
</DrawerHeader>
|
||||
|
||||
<DrawerBody style={{ flex: 1, paddingLeft: 16, paddingRight: 16, marginBottom: 0, backgroundColor: '#fff' }}>
|
||||
<Grid className="gap-4 mb-8" _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)}
|
||||
>
|
||||
<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' }} />)
|
||||
}
|
||||
}
|
||||
|
||||
return items
|
||||
})()}
|
||||
</Grid>
|
||||
</DrawerBody>
|
||||
|
||||
{showKeydown && (
|
||||
<View style={[{
|
||||
backgroundColor: '#fff',
|
||||
elevation: 30,
|
||||
}]}
|
||||
>
|
||||
<View className="p-4">
|
||||
<View className="flex flex-row items-center justify-between">
|
||||
<Pressable
|
||||
@@ -339,68 +383,70 @@ export default function AddMoneyDrawer({
|
||||
<Text className="text-3xl text-blue-700 text-right">{result}</Text>
|
||||
</View>
|
||||
|
||||
<View className="mt-1">
|
||||
<Text className="text-gray-400 text-right">{keydownInput}</Text>
|
||||
</View>
|
||||
<Text className="text-gray-400 text-right">{keydownInput}</Text>
|
||||
|
||||
<AInput
|
||||
ref={inputRef}
|
||||
value=""
|
||||
placeholder="备注"
|
||||
className="bg-[#f2f3f5] border-0 mt-2"
|
||||
className="bg-[#f2f3f5] border-0"
|
||||
size="sm"
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setIsFocused(false)}
|
||||
/>
|
||||
</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
|
||||
{!isFocused && (
|
||||
<View style={{ height: 240 }}>
|
||||
<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)}
|
||||
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',
|
||||
}}
|
||||
>
|
||||
{({ pressed }) => {
|
||||
const defaultBg = item.key === '/' ? '#e6d7b8' : '#fff'
|
||||
const pressedBg = item.key === '/' ? '#f5e9d4' : '#f2f2f2'
|
||||
return (
|
||||
<Pressable
|
||||
key={item.key}
|
||||
onPress={() => handlePress(item.key)}
|
||||
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',
|
||||
}}
|
||||
>
|
||||
{({ pressed }) => {
|
||||
const defaultBg = item.key === '/' ? '#e6d7b8' : '#fff'
|
||||
const pressedBg = item.key === '/' ? '#f5e9d4' : '#f2f2f2'
|
||||
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: pressed ? pressedBg : defaultBg,
|
||||
}}
|
||||
/>
|
||||
{item.content}
|
||||
</>
|
||||
)
|
||||
}}
|
||||
</Pressable>
|
||||
)
|
||||
})}
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
style={{
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: pressed ? pressedBg : defaultBg,
|
||||
}}
|
||||
/>
|
||||
{item.content}
|
||||
</>
|
||||
)
|
||||
}}
|
||||
</Pressable>
|
||||
)
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
</View>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
</>
|
||||
)}
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user