u
This commit is contained in:
1 parent
ac724bbdaa
commit
500fab7a80
98 files changed
+24706
-109
No files matched your search
@@ -1,9 +1,10 @@
|
||||
import type { MoneyCategoryEnum, MoneyCategoryItem } from '@/types/money/category'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { Pressable, Text, View } from 'react-native'
|
||||
import type { MoneyCategoryItem } from '@/types/money/category'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { FlatList, Pressable, Text, View } from 'react-native'
|
||||
import { AButton, ADrawer, AInput } from '@/components/common/ao'
|
||||
import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon'
|
||||
import { useMoneyCategoryStore } from '@/store/moneyCategory'
|
||||
import { MoneyCategoryEnum } from '@/types/money/category'
|
||||
|
||||
export interface EditCategoryForm {
|
||||
id?: number
|
||||
@@ -60,86 +61,104 @@ export default function CreateCategory({
|
||||
onClose?.()
|
||||
}
|
||||
|
||||
// 缓存点击 Icon 的回调
|
||||
const handlePressIcon = useCallback(
|
||||
(icon: string) => {
|
||||
setForm(v => ({ ...v, icon }))
|
||||
},
|
||||
[setForm],
|
||||
)
|
||||
|
||||
// Memo 化单个 IconItem,避免重复渲染
|
||||
const IconItem = useCallback(({ icon, selected }: { icon: string, selected: boolean }) => {
|
||||
return (
|
||||
<Pressable
|
||||
className="w-1/5 mb-3 flex items-center"
|
||||
onPress={() => handlePressIcon(icon)}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
width: 46,
|
||||
height: 46,
|
||||
borderRadius: 28,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: selected ? '#333' : '#F3F4F6',
|
||||
}}
|
||||
>
|
||||
<MoneyCategoryIcon
|
||||
name={icon}
|
||||
size={32}
|
||||
color={selected ? '#fff' : '#000'}
|
||||
/>
|
||||
</View>
|
||||
</Pressable>
|
||||
)
|
||||
}, [handlePressIcon])
|
||||
|
||||
// Memo 化渲染每组 Icon 的组件
|
||||
const renderGroup = useCallback(
|
||||
({ item }: { item: [string, string[]] }) => {
|
||||
const [groupName, icons] = item
|
||||
return (
|
||||
<View className="mb-4">
|
||||
<Text className="text-center text-sm mb-3">{groupName}</Text>
|
||||
<View className="flex flex-row flex-wrap">
|
||||
{icons.map(icon => (
|
||||
<IconItem key={icon} icon={icon} selected={form.icon === icon} />
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
},
|
||||
[IconItem, form.icon],
|
||||
)
|
||||
|
||||
// 使用 useMemo 缓存 FlatList 的数据
|
||||
const flatListData = useMemo(() => Object.entries(moneyCategoryStore.ICON_GROUPS), [moneyCategoryStore.ICON_GROUPS])
|
||||
|
||||
return (
|
||||
<ADrawer visible={isOpen} hideModal={handleClose} title="你好" Height="80%" duration={300} />
|
||||
<ADrawer
|
||||
visible={isOpen}
|
||||
hideModal={handleClose}
|
||||
height="80%"
|
||||
duration={300}
|
||||
header={(
|
||||
<View className="flex flex-row items-center justify-between w-full p-4">
|
||||
<AButton size="xs" variant="outline" onPress={handleClose}>
|
||||
取消
|
||||
</AButton>
|
||||
<Text className="text-lg font-medium">
|
||||
{type === MoneyCategoryEnum.Expense ? '添加支出分类' : '添加收入分类'}
|
||||
</Text>
|
||||
<AButton
|
||||
size="xs"
|
||||
disabled={confirmDisabled}
|
||||
loading={confirmLoading}
|
||||
onPress={async () => {
|
||||
if (!onConfirm)
|
||||
return
|
||||
try {
|
||||
setConfirmLoading(true)
|
||||
await onConfirm({ ...form, name: form.name.trim() })
|
||||
}
|
||||
finally {
|
||||
setConfirmLoading(false)
|
||||
}
|
||||
}}
|
||||
>
|
||||
确认
|
||||
</AButton>
|
||||
</View>
|
||||
)}
|
||||
>
|
||||
<FlatList
|
||||
ref={scrollRef}
|
||||
data={flatListData}
|
||||
keyExtractor={([groupName]) => groupName}
|
||||
renderItem={renderGroup}
|
||||
initialNumToRender={1}
|
||||
/>
|
||||
</ADrawer>
|
||||
)
|
||||
}
|
||||
|
||||
// <Drawer isOpen={isOpen} onClose={handleClose} size="lg" anchor="bottom">
|
||||
// <DrawerBackdrop />
|
||||
// <DrawerContent style={{ paddingLeft: 0, paddingRight: 0 }}>
|
||||
// <DrawerHeader className="px-4 flex flex-col gap-4">
|
||||
// <View className="flex flex-row items-center justify-between w-full">
|
||||
// <AButton size="xs" variant="outline" onPress={handleClose}>
|
||||
// 取消
|
||||
// </AButton>
|
||||
// <Text className="text-lg font-medium">
|
||||
// {type === MoneyCategoryEnum.Expense ? '添加支出分类' : '添加收入分类'}
|
||||
// </Text>
|
||||
// <AButton
|
||||
// size="xs"
|
||||
// disabled={confirmDisabled}
|
||||
// loading={confirmLoading}
|
||||
// onPress={async () => {
|
||||
// if (!onConfirm)
|
||||
// return
|
||||
// try {
|
||||
// setConfirmLoading(true)
|
||||
// await onConfirm({ ...form, name: form.name.trim() })
|
||||
// }
|
||||
// finally {
|
||||
// setConfirmLoading(false)
|
||||
// }
|
||||
// }}
|
||||
// >
|
||||
// 确认
|
||||
// </AButton>
|
||||
// </View>
|
||||
// <AInput
|
||||
// value={form.name}
|
||||
// placeholder="请输入名称(不超过5个字符)"
|
||||
// onChangeText={text => setForm(val => ({ ...val, name: text }))}
|
||||
// />
|
||||
// </DrawerHeader>
|
||||
|
||||
// <DrawerBody ref={scrollRef} className="mb-16">
|
||||
// {Object.entries(moneyCategoryStore.ICON_GROUPS).map(([groupName, icons]) => (
|
||||
// <View key={groupName} className="mb-4">
|
||||
// <Text className="text-center text-sm mb-3">{groupName}</Text>
|
||||
// <View className="flex flex-row flex-wrap">
|
||||
// {icons.map(icon => (
|
||||
// <Pressable
|
||||
// key={icon}
|
||||
// className="w-1/5 mb-3 flex items-center"
|
||||
// onPress={() => setForm(val => ({ ...val, icon }))}
|
||||
// >
|
||||
// <View
|
||||
// onLayout={(e) => {
|
||||
// console.log(e.nativeEvent.layout)
|
||||
// iconPositions.current[icon] = e.nativeEvent.layout.y
|
||||
// }}
|
||||
// style={{
|
||||
// width: 46,
|
||||
// height: 46,
|
||||
// borderRadius: 28,
|
||||
// justifyContent: 'center',
|
||||
// alignItems: 'center',
|
||||
// backgroundColor: icon === form.icon ? '#333' : '#F3F4F6',
|
||||
// }}
|
||||
// >
|
||||
// <MoneyCategoryIcon
|
||||
// name={icon}
|
||||
// size={32}
|
||||
// color={icon === form.icon ? '#fff' : '#000'}
|
||||
// />
|
||||
// </View>
|
||||
// </Pressable>
|
||||
// ))}
|
||||
// </View>
|
||||
// </View>
|
||||
// ))}
|
||||
// </DrawerBody>
|
||||
|
||||
// <DrawerFooter />
|
||||
// </DrawerContent>
|
||||
// </Drawer>
|
||||
@@ -19,9 +19,10 @@ interface DrawerMenuProps {
|
||||
visible: boolean
|
||||
duration?: number
|
||||
menuPosition?: 'left' | 'right' | 'top' | 'bottom'
|
||||
Height?: DimensionValue
|
||||
height?: DimensionValue
|
||||
hideModal: () => void
|
||||
children?: ReactNode
|
||||
header?: ReactNode
|
||||
isCircle?: boolean
|
||||
CircleNum?: number
|
||||
isShadowHideModal?: boolean
|
||||
@@ -30,7 +31,7 @@ interface DrawerMenuProps {
|
||||
|
||||
export default function Drawer({
|
||||
visible,
|
||||
Height,
|
||||
height,
|
||||
hideModal,
|
||||
duration = 300,
|
||||
isCircle,
|
||||
@@ -38,6 +39,7 @@ export default function Drawer({
|
||||
children,
|
||||
CircleNum,
|
||||
isShadowHideModal = true,
|
||||
header,
|
||||
title,
|
||||
}: DrawerMenuProps) {
|
||||
const [menuPositionStyle, setMenuPositionStyle] = useState<ViewStyle>()
|
||||
@@ -68,7 +70,7 @@ export default function Drawer({
|
||||
borderBottomRightRadius: isCircle ? CircleNum : 0,
|
||||
})
|
||||
setDrawerMenuBox({
|
||||
width: Height,
|
||||
width: height,
|
||||
height: WINDOW.height,
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
@@ -84,7 +86,7 @@ export default function Drawer({
|
||||
borderBottomLeftRadius: isCircle ? CircleNum : 0,
|
||||
})
|
||||
setDrawerMenuBox({
|
||||
width: Height,
|
||||
width: height,
|
||||
height: WINDOW.height,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
@@ -101,7 +103,7 @@ export default function Drawer({
|
||||
})
|
||||
setDrawerMenuBox({
|
||||
width: WINDOW.width,
|
||||
height: Height,
|
||||
height,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
@@ -118,14 +120,14 @@ export default function Drawer({
|
||||
})
|
||||
setDrawerMenuBox({
|
||||
width: WINDOW.width,
|
||||
height: Height,
|
||||
height,
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
})
|
||||
break
|
||||
}
|
||||
}, [menuPosition, Height, isCircle, CircleNum])
|
||||
}, [menuPosition, height, isCircle, CircleNum])
|
||||
|
||||
/* ================== 动画 ================== */
|
||||
const open = () => {
|
||||
@@ -219,17 +221,20 @@ export default function Drawer({
|
||||
<View style={{ paddingTop: Platform.OS === 'ios' ? 50 : 0 }} />
|
||||
)}
|
||||
|
||||
<View style={styles.headTitle}>
|
||||
<Text style={styles.title}>{title}</Text>
|
||||
<LucideIcon
|
||||
icon="X"
|
||||
size={24}
|
||||
color="black"
|
||||
style={{ position: 'absolute', right: 15, top: 11 }}
|
||||
onPress={close}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{
|
||||
header || (
|
||||
<View style={styles.headTitle}>
|
||||
<Text style={styles.title}>{title}</Text>
|
||||
<LucideIcon
|
||||
icon="X"
|
||||
size={22}
|
||||
color="black"
|
||||
style={{ position: 'absolute', right: 15, top: 11 }}
|
||||
onPress={close}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
{children}
|
||||
</View>
|
||||
</Animated.View>
|
||||
@@ -249,7 +254,6 @@ const styles = StyleSheet.create({
|
||||
position: 'absolute',
|
||||
},
|
||||
headTitle: {
|
||||
height: 40,
|
||||
width: '100%',
|
||||
padding: 10,
|
||||
justifyContent: 'center',
|
||||
|
||||
@@ -32,8 +32,8 @@ function isWhiteListed(url: string) {
|
||||
}
|
||||
|
||||
const alovaInstance = createAlova({
|
||||
baseURL: 'http://192.168.5.6:8086/app',
|
||||
// baseURL: 'http://192.168.1.137:8086/app',
|
||||
// baseURL: 'http://192.168.5.6:8086/app',
|
||||
baseURL: 'http://192.168.1.137:8086/app',
|
||||
requestAdapter: axiosRequestAdapter(),
|
||||
timeout: 5000,
|
||||
cacheFor: null,
|
||||
|
||||
Reference in new issue
Block a user