u
This commit is contained in:
1 parent
5a79414319
commit
8663cb2e3d
28 files changed
+744
-756
No files matched your search
@@ -1,43 +1,40 @@
|
||||
import type { icons } from 'lucide-react-native'
|
||||
import type { SortableGridRenderItem } from 'react-native-sortables'
|
||||
import type { NavItem } from '@/store/navigation'
|
||||
import { Slot, usePathname, useRouter } from 'expo-router'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { Pressable, Text, TouchableOpacity, Vibration, View } from 'react-native'
|
||||
import { Text, TouchableOpacity, View } from 'react-native'
|
||||
import Animated, { useAnimatedRef } from 'react-native-reanimated'
|
||||
import Sortable from 'react-native-sortables'
|
||||
import { ADrawer, LucideIcon } from '@/components/common/ao'
|
||||
|
||||
interface NavItem {
|
||||
label: string
|
||||
path: string
|
||||
icon: keyof typeof icons
|
||||
}
|
||||
|
||||
const NAV_MENUS: NavItem[] = [
|
||||
{ label: '记账', path: '/money', icon: 'CircleDollarSign' },
|
||||
{ label: '恋爱记', path: '/love', icon: 'Heart' },
|
||||
{ label: '聊天', path: '/chat', icon: 'MessageCircle' },
|
||||
{ label: '个人中心', path: '/user', icon: 'CircleUserRound' },
|
||||
]
|
||||
import { useNavStore } from '@/store/navigation'
|
||||
|
||||
export default function TabsLayout() {
|
||||
const scrollableRef = useAnimatedRef<Animated.ScrollView>()
|
||||
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const navStore = useNavStore()
|
||||
|
||||
const [showNavDrawer, setShowNavDrawer] = useState(false)
|
||||
const [draggingId, setDraggingId] = useState<string>('')
|
||||
|
||||
const [currentNav, setCurrentNav] = useState<NavItem>({
|
||||
label: '',
|
||||
path: '',
|
||||
icon: 'AArrowDown',
|
||||
label: 'Welcome',
|
||||
path: '/',
|
||||
icon: 'Sparkles',
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const current = NAV_MENUS.find(item => item.path === pathname)
|
||||
const current = navStore.navMenus.find(item => item.path === pathname)
|
||||
if (current) {
|
||||
setCurrentNav(current)
|
||||
}
|
||||
else {
|
||||
setCurrentNav({
|
||||
label: 'Welcome',
|
||||
path: '/',
|
||||
icon: 'Sparkles',
|
||||
})
|
||||
}
|
||||
}, [pathname])
|
||||
|
||||
const refreshPage = () => {
|
||||
@@ -46,15 +43,14 @@ export default function TabsLayout() {
|
||||
|
||||
const renderNavItem = useCallback<SortableGridRenderItem<NavItem>>(
|
||||
({ item }) => (
|
||||
<Pressable
|
||||
<TouchableOpacity
|
||||
className="
|
||||
flex
|
||||
flex-col
|
||||
items-center
|
||||
justify-center
|
||||
bg-[white]
|
||||
bg-[#f9f9f9]
|
||||
rounded-md
|
||||
shadow-md
|
||||
p-3
|
||||
"
|
||||
onPress={() => {
|
||||
@@ -66,7 +62,7 @@ export default function TabsLayout() {
|
||||
<Text className="text-sm mt-2">
|
||||
{item.label}
|
||||
</Text>
|
||||
</Pressable>
|
||||
</TouchableOpacity>
|
||||
),
|
||||
[],
|
||||
)
|
||||
@@ -86,6 +82,7 @@ export default function TabsLayout() {
|
||||
px-2
|
||||
gap-4
|
||||
"
|
||||
style={{ zIndex: 0 }}
|
||||
>
|
||||
<View className="bg-white rounded-md shadow-lg h-12 w-12">
|
||||
<TouchableOpacity className="w-full h-full items-center justify-center">
|
||||
@@ -128,11 +125,15 @@ export default function TabsLayout() {
|
||||
columnGap={16}
|
||||
rowGap={16}
|
||||
columns={3}
|
||||
data={NAV_MENUS}
|
||||
data={navStore.navMenus}
|
||||
keyExtractor={item => item.path}
|
||||
renderItem={renderNavItem}
|
||||
scrollableRef={scrollableRef}
|
||||
autoScrollActivationOffset={200}
|
||||
showDropIndicator
|
||||
onDragEnd={(dragData) => {
|
||||
navStore.setNavMenus(dragData.data)
|
||||
}}
|
||||
/>
|
||||
</Animated.ScrollView>
|
||||
</ADrawer>
|
||||
|
||||
Whitespace-only changes.
@@ -1,20 +1,34 @@
|
||||
import { useRouter } from 'expo-router'
|
||||
import { Text, View } from 'react-native'
|
||||
import { Image, Text, View } from 'react-native'
|
||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||
import { AButton } from '@/components/common/ao'
|
||||
// 这个页面的作用是作为占位页,避免进入 (tabs) layout 时出现 404 页面。
|
||||
// 如果想指定默认页面,可以通过 router.replace 或 TabTrigger 指向具体子页面。
|
||||
|
||||
export default function Index() {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<View>
|
||||
<AButton onPress={() => {
|
||||
router.push('/money')
|
||||
}}
|
||||
<SafeAreaView className="flex-1 bg-white">
|
||||
<View className="flex-1 items-center justify-center px-6">
|
||||
|
||||
<Image
|
||||
source={require('@/static/images/welcome.png')}
|
||||
className="w-86 h-48 mb-6"
|
||||
resizeMode="contain"
|
||||
/>
|
||||
|
||||
<Text className="text-2xl font-semibold text-gray-900 mb-3">
|
||||
🎉 欢迎使用 OneAO
|
||||
</Text>
|
||||
|
||||
<Text className="text-base text-gray-500 text-center mb-10">
|
||||
记录生活,记录情绪,也记录每一笔重要的支出
|
||||
</Text>
|
||||
|
||||
<AButton
|
||||
className="w-full"
|
||||
onPress={() => router.replace('/money')}
|
||||
>
|
||||
测试
|
||||
开始使用
|
||||
</AButton>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import { useFocusEffect, useRouter } from 'expo-router'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import { Image, Text, TouchableOpacity, View } from 'react-native'
|
||||
import { Drawer } from 'react-native-drawer-layout'
|
||||
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||
import { ADatePicker, AListItem, LucideIcon } from '@/components/common/ao'
|
||||
import { ADatePicker, ADrawer, AListItem, LucideIcon } from '@/components/common/ao'
|
||||
import { Fab, FabIcon } from '@/components/ui/fab'
|
||||
import { AddIcon } from '@/components/ui/icon'
|
||||
import { queryMoneyRecordsApi } from '@/request/api/money/record'
|
||||
import { useAppStore } from '@/store/app'
|
||||
import { useMoneyRecordStore } from '@/store/moneyRecord'
|
||||
import { getCurrentYearMonth } from '@/utils/time'
|
||||
import { toast } from '@/utils/toast'
|
||||
import TransactionsList from './components/TransactionsList'
|
||||
|
||||
export default function Money() {
|
||||
const appStore = useAppStore()
|
||||
const moneyRecordStore = useMoneyRecordStore()
|
||||
const router = useRouter()
|
||||
// 安全高度
|
||||
@@ -47,12 +44,6 @@ export default function Money() {
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!appStore.ready)
|
||||
return
|
||||
getMoneyRecords()
|
||||
}, [appStore.ready, searchParams])
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
// 页面显示 / 返回时
|
||||
@@ -68,120 +59,78 @@ export default function Money() {
|
||||
<View
|
||||
className="flex-1"
|
||||
>
|
||||
<Drawer
|
||||
open={showActionsMenu}
|
||||
onOpen={() => setShowActionsMenu(true)}
|
||||
onClose={() => setShowActionsMenu(false)}
|
||||
drawerPosition="right"
|
||||
drawerStyle={{
|
||||
width: '70%',
|
||||
}}
|
||||
renderDrawerContent={() => {
|
||||
return (
|
||||
<SafeAreaView className="flex-col px-3">
|
||||
<Image
|
||||
source={require('@/static/images/logo.png')}
|
||||
style={{ width: 40, height: 40 }}
|
||||
className="self-center"
|
||||
/>
|
||||
|
||||
<View className="mt-2">
|
||||
<Text className="text-gray-600 font-semibold text-sm">管理功能</Text>
|
||||
|
||||
<View className="p-1">
|
||||
<AListItem
|
||||
icon="LayoutGrid"
|
||||
text="类别设置"
|
||||
onPress={() => {
|
||||
router.navigate('/money/category/setting')
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="mt-2">
|
||||
<Text className="text-gray-600 font-semibold text-sm">统计分析</Text>
|
||||
|
||||
<View className="p-1">
|
||||
<AListItem icon="ChartSpline" text="图表分析" />
|
||||
</View>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
)
|
||||
<View
|
||||
style={{
|
||||
paddingTop: insets.top,
|
||||
backgroundColor: '#fff',
|
||||
elevation: 3,
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
paddingTop: insets.top,
|
||||
backgroundColor: '#fff',
|
||||
elevation: 3,
|
||||
}}
|
||||
>
|
||||
<View className="flex flex-row justify-between items-center px-3">
|
||||
<TouchableOpacity
|
||||
onPress={() => setShowDatePicker(true)}
|
||||
className="flex flex-row items-center gap-1"
|
||||
>
|
||||
<Text className="font-semibold text-lg">{searchParams.record_time}</Text>
|
||||
<LucideIcon icon="ChevronDown" size={16} color="#666" clickable={false} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
className="flex flex-row items-center gap-2"
|
||||
onPress={() => {
|
||||
setShowActionsMenu(true)
|
||||
}}
|
||||
>
|
||||
<LucideIcon icon="Menu" size={24} clickable={false} />
|
||||
</TouchableOpacity>
|
||||
|
||||
</View>
|
||||
|
||||
<View
|
||||
className="px-3 py-3"
|
||||
<View className="flex flex-row justify-between items-center px-3">
|
||||
<TouchableOpacity
|
||||
onPress={() => setShowDatePicker(true)}
|
||||
className="flex flex-row items-center gap-1"
|
||||
>
|
||||
<View
|
||||
className="flex flex-row gap-4"
|
||||
style={{
|
||||
borderBottomLeftRadius: 16,
|
||||
borderBottomRightRadius: 18,
|
||||
}}
|
||||
>
|
||||
<View className="flex-1">
|
||||
<Text className="text-gray-500 text-sm">收入</Text>
|
||||
<Text
|
||||
className="text-lg font-semibold mt-0.5"
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{moneyRecordStore.getTotalIncome()}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className="font-semibold text-lg">{searchParams.record_time}</Text>
|
||||
<LucideIcon icon="ChevronDown" size={16} color="#666" clickable={false} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<View className="flex-1">
|
||||
<Text className="text-gray-500 text-sm">支出</Text>
|
||||
<Text
|
||||
className="text-lg font-semibold mt-0.5"
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{moneyRecordStore.getTotalExpense()}
|
||||
</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
className="flex flex-row items-center gap-2"
|
||||
onPress={() => {
|
||||
setShowActionsMenu(true)
|
||||
}}
|
||||
>
|
||||
<LucideIcon icon="Menu" size={24} clickable={false} />
|
||||
</TouchableOpacity>
|
||||
|
||||
<View className="flex-1">
|
||||
<Text className="text-gray-500 text-sm">结余</Text>
|
||||
<Text
|
||||
className="text-lg font-semibold mt-0.5"
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{moneyRecordStore.getTotalBalance()}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View
|
||||
className="px-3 py-3"
|
||||
>
|
||||
<View
|
||||
className="flex flex-row gap-4"
|
||||
style={{
|
||||
borderBottomLeftRadius: 16,
|
||||
borderBottomRightRadius: 18,
|
||||
}}
|
||||
>
|
||||
<View className="flex-1">
|
||||
<Text className="text-gray-500 text-sm">收入</Text>
|
||||
<Text
|
||||
className="text-lg font-semibold mt-0.5"
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{moneyRecordStore.getTotalIncome()}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* <View
|
||||
<View className="flex-1">
|
||||
<Text className="text-gray-500 text-sm">支出</Text>
|
||||
<Text
|
||||
className="text-lg font-semibold mt-0.5"
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{moneyRecordStore.getTotalExpense()}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className="flex-1">
|
||||
<Text className="text-gray-500 text-sm">结余</Text>
|
||||
<Text
|
||||
className="text-lg font-semibold mt-0.5"
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{moneyRecordStore.getTotalBalance()}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* <View
|
||||
className="flex-row items-center gap-3 mt-2"
|
||||
style={{
|
||||
borderBottomLeftRadius: 8,
|
||||
@@ -196,58 +145,98 @@ export default function Money() {
|
||||
</View>
|
||||
<Text className="text-xs text-blue-500">点击设置</Text>
|
||||
</View> */}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="flex-1 mt-2">
|
||||
<TransactionsList
|
||||
records={moneyRecordStore.records}
|
||||
onUpdate={(data) => {
|
||||
router.navigate({
|
||||
pathname: '/money/record/editor',
|
||||
params: { id: data.id },
|
||||
})
|
||||
}}
|
||||
onDetail={(id) => {
|
||||
router.navigate({
|
||||
pathname: '/money/record/detail',
|
||||
params: { id },
|
||||
})
|
||||
}}
|
||||
onDelete={(id) => {
|
||||
moneyRecordStore.deleteMoneyRecord(id)
|
||||
}}
|
||||
onRefreshData={() => {
|
||||
getMoneyRecords()
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Fab
|
||||
size="lg"
|
||||
onPress={() => {
|
||||
router.navigate('/money/record/editor')
|
||||
}}
|
||||
>
|
||||
<FabIcon as={AddIcon} size="xl" />
|
||||
</Fab>
|
||||
|
||||
<ADatePicker
|
||||
show={showDatePicker}
|
||||
mode="month"
|
||||
date={searchParams.record_time}
|
||||
onConfirm={(val) => {
|
||||
setSearchParams({
|
||||
...searchParams,
|
||||
record_time: val,
|
||||
<View className="flex-1 mt-2">
|
||||
<TransactionsList
|
||||
records={moneyRecordStore.records}
|
||||
onUpdate={(data) => {
|
||||
router.navigate({
|
||||
pathname: '/money/record/editor',
|
||||
params: { id: data.id },
|
||||
})
|
||||
setShowDatePicker(false)
|
||||
}}
|
||||
onClose={() => {
|
||||
setShowDatePicker(false)
|
||||
onDetail={(id) => {
|
||||
router.navigate({
|
||||
pathname: '/money/record/detail',
|
||||
params: { id },
|
||||
})
|
||||
}}
|
||||
onDelete={(id) => {
|
||||
moneyRecordStore.deleteMoneyRecord(id)
|
||||
}}
|
||||
onRefreshData={() => {
|
||||
getMoneyRecords()
|
||||
}}
|
||||
/>
|
||||
</Drawer>
|
||||
</View>
|
||||
|
||||
<Fab
|
||||
size="lg"
|
||||
onPress={() => {
|
||||
router.navigate('/money/record/editor')
|
||||
}}
|
||||
className="mb-20"
|
||||
>
|
||||
<FabIcon as={AddIcon} size="xl" />
|
||||
</Fab>
|
||||
|
||||
<ADatePicker
|
||||
show={showDatePicker}
|
||||
mode="month"
|
||||
date={searchParams.record_time}
|
||||
onConfirm={(val) => {
|
||||
setSearchParams({
|
||||
...searchParams,
|
||||
record_time: val,
|
||||
})
|
||||
setShowDatePicker(false)
|
||||
}}
|
||||
onClose={() => {
|
||||
setShowDatePicker(false)
|
||||
}}
|
||||
/>
|
||||
|
||||
<ADrawer
|
||||
visible={showActionsMenu}
|
||||
hideModal={() => {
|
||||
setShowActionsMenu(false)
|
||||
}}
|
||||
menuPosition="right"
|
||||
height="60%"
|
||||
showHeader={false}
|
||||
>
|
||||
<SafeAreaView className="flex-col px-3">
|
||||
<Image
|
||||
source={require('@/static/images/logo.png')}
|
||||
style={{ width: 40, height: 40 }}
|
||||
className="self-center"
|
||||
/>
|
||||
|
||||
<View className="mt-2">
|
||||
<Text className="text-gray-600 font-semibold text-sm">管理功能</Text>
|
||||
|
||||
<View className="p-1">
|
||||
<AListItem
|
||||
icon="LayoutGrid"
|
||||
text="类别设置"
|
||||
onPress={() => {
|
||||
router.navigate('/money/category/setting')
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="mt-2">
|
||||
<Text className="text-gray-600 font-semibold text-sm">统计分析</Text>
|
||||
|
||||
<View className="p-1">
|
||||
<AListItem icon="ChartSpline" text="图表分析" />
|
||||
</View>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</ADrawer>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user