This commit is contained in:
oneao committed 2026-01-20 22:13:59 +08:00
1 parent 2130be4e49
commit 1ccae92d0f
8 files changed
+96 -55

No files matched your search

+4 -4
View File
@@ -1,13 +1,13 @@
{ {
"expo": { "expo": {
"name": "base-app", "name": "allapp",
"slug": "base-app", "slug": "allapp",
"version": "1.0.0", "version": "1.0.0",
"orientation": "portrait", "orientation": "portrait",
"icon": "./assets/icon.png", "icon": "./assets/icon.png",
"userInterfaceStyle": "light", "userInterfaceStyle": "light",
"newArchEnabled": true, "newArchEnabled": true,
"scheme": "oneao", "scheme": "allapp",
"splash": { "splash": {
"image": "./assets/splash-icon.png", "image": "./assets/splash-icon.png",
"resizeMode": "contain", "resizeMode": "contain",
@@ -23,7 +23,7 @@
}, },
"edgeToEdgeEnabled": true, "edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false, "predictiveBackGestureEnabled": false,
"package": "com.oneao.baseapp" "package": "cn.oneao.allapp"
}, },
"web": { "web": {
"favicon": "./assets/favicon.png" "favicon": "./assets/favicon.png"
+2 -2
View File
@@ -1,5 +1,5 @@
{ {
"name": "base-app", "name": "allapp",
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"main": "expo-router/entry", "main": "expo-router/entry",
@@ -47,6 +47,7 @@
"react-native-keyboard-controller": "1.18.5", "react-native-keyboard-controller": "1.18.5",
"react-native-pager-view": "6.9.1", "react-native-pager-view": "6.9.1",
"react-native-popup-menu": "^0.18.0", "react-native-popup-menu": "^0.18.0",
"react-native-qq-lib": "git+https://github.com/haxibiao/react-native-qq-lib.git",
"react-native-qrcode-svg": "^6.3.20", "react-native-qrcode-svg": "^6.3.20",
"react-native-reanimated": "~4.1.1", "react-native-reanimated": "~4.1.1",
"react-native-safe-area-context": "~5.6.1", "react-native-safe-area-context": "~5.6.1",
@@ -54,7 +55,6 @@
"react-native-sortables": "^1.9.3", "react-native-sortables": "^1.9.3",
"react-native-svg": "15.12.1", "react-native-svg": "15.12.1",
"react-native-web": "^0.21.0", "react-native-web": "^0.21.0",
"react-native-worklets": "0.5.1",
"tailwind-merge": "^3.4.0", "tailwind-merge": "^3.4.0",
"zustand": "^5.0.8" "zustand": "^5.0.8"
}, },
+15 -3
View File
@@ -119,6 +119,9 @@ importers:
react-native-popup-menu: react-native-popup-menu:
specifier: ^0.18.0 specifier: ^0.18.0
version: 0.18.0 version: 0.18.0
react-native-qq-lib:
specifier: git+https://github.com/haxibiao/react-native-qq-lib.git
version: git+https://github.com/haxibiao/react-native-qq-lib.git#da1a25d40a31a18b85ce35c55737a5d7af40a2c9(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
react-native-qrcode-svg: react-native-qrcode-svg:
specifier: ^6.3.20 specifier: ^6.3.20
version: 6.3.20(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 6.3.20(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
@@ -140,9 +143,6 @@ importers:
react-native-web: react-native-web:
specifier: ^0.21.0 specifier: ^0.21.0
version: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) version: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react-native-worklets:
specifier: 0.5.1
version: 0.5.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
tailwind-merge: tailwind-merge:
specifier: ^3.4.0 specifier: ^3.4.0
version: 3.4.0 version: 3.4.0
@@ -4947,6 +4947,13 @@ packages:
react-native-popup-menu@0.18.0: react-native-popup-menu@0.18.0:
resolution: {integrity: sha512-XD3gyp/hwL5YWw2J034DerfvbJ6S2YHqAzvqAFRU+UGnFD4JyTqggfm4UyynBD26O1PDoRb45Loil+NZCGfCnA==} resolution: {integrity: sha512-XD3gyp/hwL5YWw2J034DerfvbJ6S2YHqAzvqAFRU+UGnFD4JyTqggfm4UyynBD26O1PDoRb45Loil+NZCGfCnA==}
react-native-qq-lib@git+https://github.com/haxibiao/react-native-qq-lib.git#da1a25d40a31a18b85ce35c55737a5d7af40a2c9:
resolution: {commit: da1a25d40a31a18b85ce35c55737a5d7af40a2c9, repo: https://github.com/haxibiao/react-native-qq-lib.git, type: git}
version: 3.1.0
peerDependencies:
react: ^16.8.1
react-native: '>=0.60.0-rc.0 <1.0.x'
react-native-qrcode-svg@6.3.20: react-native-qrcode-svg@6.3.20:
resolution: {integrity: sha512-GDP7T3DDEHUo53xmDyWWXXm3MhWRp0YayqVMum98JYfm0DW2rEbz1GIj+XLaA0QX443G0nURyzPnuQJeHjuvjA==} resolution: {integrity: sha512-GDP7T3DDEHUo53xmDyWWXXm3MhWRp0YayqVMum98JYfm0DW2rEbz1GIj+XLaA0QX443G0nURyzPnuQJeHjuvjA==}
peerDependencies: peerDependencies:
@@ -11994,6 +12001,11 @@ snapshots:
react-native-popup-menu@0.18.0: {} react-native-popup-menu@0.18.0: {}
react-native-qq-lib@git+https://github.com/haxibiao/react-native-qq-lib.git#da1a25d40a31a18b85ce35c55737a5d7af40a2c9(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies:
react: 19.1.0
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
react-native-qrcode-svg@6.3.20(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): react-native-qrcode-svg@6.3.20(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies: dependencies:
prop-types: 15.8.1 prop-types: 15.8.1
@@ -35,7 +35,7 @@ export default function Money() {
}).then((res) => { }).then((res) => {
if (res.isSuccess) { if (res.isSuccess) {
console.log(res.data.records) console.log(res.data.records)
moneyRecordStore.setRecords(res.data.records, searchParams.record_time) moneyRecordStore.setRecords(res.data.records || [], searchParams.record_time)
} }
else { else {
toast.show({ toast.show({
@@ -1,5 +1,7 @@
import { useRouter } from 'expo-router' import { useRouter } from 'expo-router'
import { useEffect } from 'react'
import { Image, Text, View } from 'react-native' import { Image, Text, View } from 'react-native'
import * as QQAPI from 'react-native-qq-lib'
import CustomHeader from '@/components/custom/Header' import CustomHeader from '@/components/custom/Header'
import { Button, ButtonText } from '@/components/ui/button' import { Button, ButtonText } from '@/components/ui/button'
@@ -10,6 +12,10 @@ export default function AuthIndex() {
router.push(url) router.push(url)
} }
useEffect(() => {
QQAPI.login()
}, [])
return ( return (
<View className="flex-1"> <View className="flex-1">
<CustomHeader <CustomHeader
@@ -1,24 +1,40 @@
import type { FlatList } from 'react-native' import type { ViewStyle } from 'react-native'
import type { MoneyCategoryItem } from '@/types/money/category' import type { MoneyCategoryItem } from '@/types/money/category'
import React, { useEffect, useRef } from 'react' import React, { useEffect, useMemo, useRef } from 'react'
import { Pressable, Text, View } from 'react-native' import { FlatList, Pressable, Text, View } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler'
import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon' import MoneyCategoryIcon from '@/components/common/MoneyCategoryIcon'
import { Grid, GridItem } from '@/components/ui/grid'
interface CategoryGridProps { interface CategoryGridProps {
data: MoneyCategoryItem[] data: MoneyCategoryItem[]
selectedCategory?: MoneyCategoryItem | null selectedCategory?: MoneyCategoryItem | null
onSelectCategory?: (item: MoneyCategoryItem | null) => void onSelectCategory?: (item: MoneyCategoryItem | null) => void
className?: string
style?: ViewStyle
} }
export default function CategoryGrid({ export default function CategoryGrid({
data, data,
selectedCategory, selectedCategory,
onSelectCategory, onSelectCategory,
className,
style,
}: CategoryGridProps) { }: CategoryGridProps) {
const flatListRef = useRef<FlatList<any>>(null) const flatListRef = useRef<FlatList<any>>(null)
// 每行 4 个,补齐空项
const memoItems = useMemo(() => {
const items = [...data]
const remainder = items.length % 4
if (remainder > 0) {
const emptyCount = 4 - remainder
for (let i = 0; i < emptyCount; i++) {
items.push({ id: `empty-${i}` } as any)
}
}
return items
}, [data])
// 自动滚动到选中行 // 自动滚动到选中行
useEffect(() => { useEffect(() => {
if (!selectedCategory || !flatListRef.current) if (!selectedCategory || !flatListRef.current)
@@ -41,43 +57,51 @@ export default function CategoryGrid({
}, [selectedCategory]) }, [selectedCategory])
return ( return (
<ScrollView> <FlatList
<Grid className="gap-4 px-2 py-4 justify-start" _extra={{ className: 'grid-cols-12' }}> ref={flatListRef}
{data.map((item) => { data={memoItems}
const isSelected = selectedCategory?.id === item.id numColumns={4}
return ( keyExtractor={item => item.id.toString()}
<GridItem showsVerticalScrollIndicator={false}
_extra={{ className: 'col-span-3' }} className={`${className}`}
key={item.id} style={[style]}
getItemLayout={(data, index) => {
return { length: 80, offset: 80 * index, index }
}}
renderItem={({ item }) => {
if (!('name' in item))
return <View style={{ flex: 1 / 4, margin: 4 }} />
const isSelected = selectedCategory?.id === item.id
return (
<Pressable
style={{ flex: 1 / 4, height: 80, alignItems: 'center' }}
onPress={() => onSelectCategory?.(item)}
>
<View
style={{
width: 46,
height: 46,
borderRadius: 28,
marginTop: 4,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: isSelected ? '#333' : '#F3F4F6',
}}
> >
<Pressable <MoneyCategoryIcon
style={{ alignItems: 'center' }} name={item.icon}
onPress={() => onSelectCategory?.(item)} size={28}
> color={isSelected ? '#fff' : '#000'}
<View />
style={{ </View>
width: 46, <Text style={{ marginBottom: 4, fontSize: 14, textAlign: 'center' }}>
height: 46, {item.name}
borderRadius: 28, </Text>
justifyContent: 'center', </Pressable>
alignItems: 'center', )
backgroundColor: isSelected ? '#333' : '#F3F4F6', }}
}} />
>
<MoneyCategoryIcon
name={item.icon}
size={28}
color={isSelected ? '#fff' : '#000'}
/>
</View>
<Text style={{ fontSize: 14, textAlign: 'center' }}>
{item.name}
</Text>
</Pressable>
</GridItem>
)
})}
</Grid>
</ScrollView>
) )
} }
@@ -6,7 +6,6 @@ import { useEffect, useState } from 'react'
import { Pressable, View } from 'react-native' import { Pressable, View } from 'react-native'
import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler' import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler'
import Animated, { useAnimatedStyle, useSharedValue, withSequence, withTiming } from 'react-native-reanimated' import Animated, { useAnimatedStyle, useSharedValue, withSequence, withTiming } from 'react-native-reanimated'
import { scheduleOnRN } from 'react-native-worklets'
interface AppTabbarProps { interface AppTabbarProps {
data: TabbarItem[] data: TabbarItem[]
+2 -2
View File
@@ -32,8 +32,8 @@ function isWhiteListed(url: string) {
} }
const alovaInstance = createAlova({ const alovaInstance = createAlova({
// baseURL: 'http://192.168.5.6:8086/app', baseURL: 'http://192.168.5.6:8086/app',
baseURL: 'http://192.168.1.137:8086/app', // baseURL: 'http://192.168.1.137:8086/app',
requestAdapter: axiosRequestAdapter(), requestAdapter: axiosRequestAdapter(),
timeout: 5000, timeout: 5000,
cacheFor: null, cacheFor: null,