This commit is contained in:
oneao committed 2026-01-28 22:32:28 +08:00
1 parent d9c49b34db
commit d33cef825a
36 files changed
+753 -1077

No files matched your search

@@ -33,10 +33,10 @@ export default function CreateCategory({
const [form, setForm] = useState<EditCategoryForm>({ icon: '', name: '' })
const [confirmDisabled, setConfirmDisabled] = useState(true)
const [confirmLoading, setConfirmLoading] = useState(false)
const flatListData = Object.entries(moneyCategoryStore.ICON_GROUPS)
const flatListData2 = Object.values(moneyCategoryStore.ICON_GROUPS).flat()
const scrollRef = useRef<any>(null)
const iconPositions = useRef<Record<string, number>>({}) // 记录每个 icon 的 y 坐标
const flatListRef = useRef<FlatList<any>>(null)
// Drawer 打开/关闭控制
useEffect(() => {
setIsOpen(open)
@@ -47,6 +47,22 @@ export default function CreateCategory({
// 确认按钮状态
useEffect(() => {
setConfirmDisabled(!(form.name && form.name.length <= 5 && form.icon))
const itemIndex = flatListData2.findIndex(item => item === form.icon)
if (itemIndex === -1 || !flatListRef.current)
return
if (form.icon) {
setTimeout(() => {
if (flatListRef.current) {
flatListRef.current.scrollToIndex({
index: Math.floor(itemIndex / 5),
animated: true,
viewPosition: 0.5,
})
}
}, 0)
}
}, [form.name, form.icon])
// 编辑已有分类时填充数据
@@ -61,62 +77,55 @@ 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 的组件
// 渲染每组 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} />
))}
{icons.map((icon) => {
const selected = form.icon === icon
return (
<Pressable
key={icon}
className="w-1/5 mb-3 flex items-center"
onPress={() =>
setForm(v => ({
...v,
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>
)
})}
</View>
</View>
)
},
[IconItem, form.icon],
[form.icon],
)
// 使用 useMemo 缓存 FlatList 的数据
const flatListData = useMemo(() => Object.entries(moneyCategoryStore.ICON_GROUPS), [moneyCategoryStore.ICON_GROUPS])
return (
<ADrawer
visible={isOpen}
@@ -153,10 +162,13 @@ export default function CreateCategory({
)}
>
<FlatList
ref={scrollRef}
ref={flatListRef}
data={flatListData}
keyExtractor={([groupName]) => groupName}
renderItem={renderGroup}
getItemLayout={(data, index) => {
return { length: 80, offset: 80 * index, index }
}}
/>
</ADrawer>
)
@@ -88,13 +88,6 @@ export default function MoenyRecordEditor() {
record_time: moneyRecord.record_time,
}).then((res) => {
if (res.isSuccess) {
const result: MoneyRecord = {
...moneyRecord,
category_id: selectedCategory.id,
}
moneyRecordStore.updateMoneyRecord(result)
router.back()
}
}).catch((err) => {
@@ -110,13 +103,6 @@ export default function MoenyRecordEditor() {
})
.then((res) => {
if (res.isSuccess) {
const result: MoneyRecord = {
...res.data,
category_id: selectedCategory.id,
}
moneyRecordStore.addMoneyRecord(result)
router.back()
}
else {