From 68a834dd187944f82a5bf0172ad4577dcc0aca6e Mon Sep 17 00:00:00 2001 From: oneao Date: Wed, 12 Nov 2025 22:38:50 +0800 Subject: [PATCH] u --- code/base-project/base-app/package.json | 3 + code/base-project/base-app/pnpm-lock.yaml | 62 +++- .../base-app/src/app/(tabs)/chat.tsx | 50 ++- .../app/(tabs)/money/components/AddDrawer.tsx | 316 ++++++++++-------- .../src/components/common/ao/Input.tsx | 114 ++++--- .../base-app/src/request/index.ts | 4 +- 6 files changed, 331 insertions(+), 218 deletions(-) diff --git a/code/base-project/base-app/package.json b/code/base-project/base-app/package.json index a56f0ee8..2d98ece4 100644 --- a/code/base-project/base-app/package.json +++ b/code/base-project/base-app/package.json @@ -35,8 +35,11 @@ "react": "19.1.0", "react-native": "0.81.5", "react-native-calendars": "^1.1313.0", + "react-native-date-picker": "^5.0.13", "react-native-dates-picker": "^0.2.0", "react-native-gesture-handler": "~2.28.0", + "react-native-keyboard-aware-scroll-view": "^0.9.5", + "react-native-keyboard-controller": "1.18.5", "react-native-reanimated": "~4.1.3", "react-native-safe-area-context": "~5.6.1", "react-native-screens": "~4.16.0", diff --git a/code/base-project/base-app/pnpm-lock.yaml b/code/base-project/base-app/pnpm-lock.yaml index 4a70f61d..9c312815 100644 --- a/code/base-project/base-app/pnpm-lock.yaml +++ b/code/base-project/base-app/pnpm-lock.yaml @@ -83,12 +83,21 @@ importers: react-native-calendars: specifier: ^1.1313.0 version: 1.1313.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-date-picker: + specifier: ^5.0.13 + version: 5.0.13(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-dates-picker: specifier: ^0.2.0 version: 0.2.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-gesture-handler: specifier: ~2.28.0 version: 2.28.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-keyboard-aware-scroll-view: + specifier: ^0.9.5 + version: 0.9.5(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)) + react-native-keyboard-controller: + specifier: 1.18.5 + version: 1.18.5(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@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))(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-reanimated: specifier: ~4.1.3 version: 4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@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))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) @@ -3746,56 +3755,48 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-gnu@1.30.2: resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.27.0: resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.27.0: resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.27.0: resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.27.0: resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==} @@ -4651,6 +4652,12 @@ packages: react-native-svg: optional: true + react-native-date-picker@5.0.13: + resolution: {integrity: sha512-qCLUODZVsJetO5zuoXjw1D39K527XWqBG8sOfhWdHyPzf13h8RXR1/RSKd1N0fdRDi5GdyizYmB0lPAK12/hbw==} + peerDependencies: + react: '>= 17.0.1' + react-native: '>= 0.64.3' + react-native-dates-picker@0.2.0: resolution: {integrity: sha512-dO7HGami3fhKa/WVtd5jj0xfekbNJZzka++4+0pBUW8br2/t9YzyJ7DYPcZ7vGdRy6bw/qkBG6EASRq8DJP/5Q==} engines: {node: '>= 16.0.0'} @@ -4672,12 +4679,29 @@ packages: react-native: '*' react-native-svg: '>=9.7.0' + react-native-iphone-x-helper@1.3.1: + resolution: {integrity: sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==} + peerDependencies: + react-native: '>=0.42.0' + react-native-is-edge-to-edge@1.2.1: resolution: {integrity: sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==} peerDependencies: react: '*' react-native: '*' + react-native-keyboard-aware-scroll-view@0.9.5: + resolution: {integrity: sha512-XwfRn+T/qBH9WjTWIBiJD2hPWg0yJvtaEw6RtPCa5/PYHabzBaWxYBOl0usXN/368BL1XktnZPh8C2lmTpOREA==} + peerDependencies: + react-native: '>=0.48.4' + + react-native-keyboard-controller@1.18.5: + resolution: {integrity: sha512-wbYN6Tcu3G5a05dhRYBgjgd74KqoYWuUmroLpigRg9cXy5uYo7prTMIvMgvLtARQtUF7BOtFggUnzgoBOgk0TQ==} + peerDependencies: + react: '*' + react-native: '*' + react-native-reanimated: '>=3.0.0' + react-native-reanimated@4.1.3: resolution: {integrity: sha512-GP8wsi1u3nqvC1fMab/m8gfFwFyldawElCcUSBJQgfrXeLmsPPUOpDw44lbLeCpcwUuLa05WTVePdTEwCLTUZg==} peerDependencies: @@ -11441,6 +11465,11 @@ snapshots: transitivePeerDependencies: - supports-color + react-native-date-picker@5.0.13(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-dates-picker@0.2.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: dayjs: 1.11.19 @@ -11470,11 +11499,28 @@ snapshots: transitivePeerDependencies: - supports-color + react-native-iphone-x-helper@1.3.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)): + dependencies: + react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) + react-native-is-edge-to-edge@1.2.1(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-keyboard-aware-scroll-view@0.9.5(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)): + dependencies: + prop-types: 15.8.1 + react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) + react-native-iphone-x-helper: 1.3.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)) + + react-native-keyboard-controller@1.18.5(react-native-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@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))(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: + 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-is-edge-to-edge: 1.2.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-reanimated: 4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@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))(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-reanimated@4.1.3(@babel/core@7.28.5)(react-native-worklets@0.5.2(@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))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: '@babel/core': 7.28.5 diff --git a/code/base-project/base-app/src/app/(tabs)/chat.tsx b/code/base-project/base-app/src/app/(tabs)/chat.tsx index c0d9520e..06b86c1b 100644 --- a/code/base-project/base-app/src/app/(tabs)/chat.tsx +++ b/code/base-project/base-app/src/app/(tabs)/chat.tsx @@ -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() +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 ( - setSelected(date)} - styles={defaultStyles} - className="mt-22" - /> + + + + {/* 输入框 */} + + + + ) } - \ No newline at end of file + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + content: { + flex: 1, + justifyContent: 'space-between', + }, + topSpace: { + flex: 1, + }, + inputWrapper: { + marginHorizontal: 16, + marginBottom: 20, + }, +}) diff --git a/code/base-project/base-app/src/app/(tabs)/money/components/AddDrawer.tsx b/code/base-project/base-app/src/app/(tabs)/money/components/AddDrawer.tsx index d8c1b69c..4642bf39 100644 --- a/code/base-project/base-app/src/app/(tabs)/money/components/AddDrawer.tsx +++ b/code/base-project/base-app/src/app/(tabs)/money/components/AddDrawer.tsx @@ -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(null) + + const [isFocused, setIsFocused] = useState(false) + + // 监听键盘收起 + useEffect(() => { + const sub = Keyboard.addListener('keyboardDidHide', () => { + if (inputRef.current) { + inputRef.current.blur() // 收起键盘时失去焦点 + setIsFocused(false) + } + }) + return () => sub.remove() + }, []) + return ( - <> - - - - - - - - 取消 - - - - - {(() => { - const list = selectedIndex === 0 ? categories.income : categories.expense - const items = list.map((item) => { - const isSelected = selectedCategoryId === item.id - return ( - - selectCategory(item)} - > - - - - - {item.name} - - - - ) - }) - - const remainder = list.length % 4 - if (remainder > 0) { - const emptyCount = 4 - remainder - for (let i = 0; i < emptyCount; i++) { - items.push() - } - } - - return items - })()} - - - - - - setShowKeydown(false)} - > - + + + - + + + + 取消 + + + + + + {(() => { + const list = selectedIndex === 0 ? categories.income : categories.expense + const items = list.map((item) => { + const isSelected = selectedCategoryId === item.id + return ( + + selectCategory(item)} + > + + + + + {item.name} + + + + ) + }) + + const remainder = list.length % 4 + if (remainder > 0) { + const emptyCount = 4 - remainder + for (let i = 0; i < emptyCount; i++) { + items.push() + } + } + + return items + })()} + + + + {showKeydown && ( + {result} - - {keydownInput} - + {keydownInput} setIsFocused(true)} + onBlur={() => setIsFocused(false)} /> - - - {keys.map((item, idx) => { - const isFirstCol = idx % 4 === 0 - const isFirstRow = idx < 4 - const isLastCol = (idx + 1) % 4 === 0 - const isLastRow = idx >= 12 + {!isFocused && ( + + + {keys.map((item, idx) => { + const isFirstCol = idx % 4 === 0 + const isFirstRow = idx < 4 + const isLastCol = (idx + 1) % 4 === 0 + const isLastRow = idx >= 12 - return ( - 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 ( + 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 ( - <> - - {item.content} - - ) - }} - - ) - })} + return ( + <> + + {item.content} + + ) + }} + + ) + })} + - + )} - - - - + )} + + ) } diff --git a/code/base-project/base-app/src/components/common/ao/Input.tsx b/code/base-project/base-app/src/components/common/ao/Input.tsx index a36de902..be17f37c 100644 --- a/code/base-project/base-app/src/components/common/ao/Input.tsx +++ b/code/base-project/base-app/src/components/common/ao/Input.tsx @@ -1,13 +1,11 @@ import type { ComponentType } from 'react' -import type { StyleProp, ViewStyle } from 'react-native' -import { useState } from 'react' +import type { StyleProp, TextInputProps, ViewStyle } from 'react-native' +import React, { forwardRef, useState } from 'react' import { Pressable } from 'react-native' import { EyeIcon, EyeOffIcon } from '@/components/ui/icon' import { InputField, InputIcon, InputSlot, Input as NativeInput } from '@/components/ui/input' -export interface AInputProps { - value: string - onChange?: (text: string) => void +export interface AInputProps extends Omit { isPassword?: boolean isDisabled?: boolean isReadOnly?: boolean @@ -16,62 +14,62 @@ export interface AInputProps { isFocused?: boolean variant?: 'outline' | 'rounded' | 'underlined' size?: 'sm' | 'md' | 'lg' | 'xl' - placeholder?: string leftIcon?: ComponentType className?: string style?: StyleProp } -export default function Input({ - value, - onChange, - isPassword = false, - isDisabled = false, - isReadOnly = false, - isInvalid = false, - isHovered = false, - isFocused = false, - variant = 'outline', - size = 'md', - placeholder, - leftIcon, - className, - style, - ...rest -}: AInputProps) { - const [showPassword, setShowPassword] = useState(false) +const AInput = forwardRef, AInputProps>( + ({ + isPassword = false, + isDisabled = false, + isReadOnly = false, + isInvalid = false, + isHovered = false, + isFocused = false, + variant = 'outline', + size = 'md', + leftIcon, + className, + style, + ...rest + }, ref) => { + const [showPassword, setShowPassword] = useState(false) - return ( - - {leftIcon && ( - - - - )} - - {isPassword && ( - - setShowPassword(prev => !prev)}> - - - - )} - - ) -} + return ( + + {leftIcon && ( + + + + )} + + + + {isPassword && ( + + setShowPassword(prev => !prev)}> + + + + )} + + ) + }, +) + +export default AInput diff --git a/code/base-project/base-app/src/request/index.ts b/code/base-project/base-app/src/request/index.ts index 6c068bd8..4085918d 100644 --- a/code/base-project/base-app/src/request/index.ts +++ b/code/base-project/base-app/src/request/index.ts @@ -30,8 +30,8 @@ function isWhiteListed(url: string) { } const alovaInstance = createAlova({ - // baseURL: 'http://192.168.5.6:8085/app', - baseURL: 'http://192.168.1.136:8085/app', + baseURL: 'http://192.168.5.6:8085/app', + // baseURL: 'http://192.168.1.136:8085/app', requestAdapter: axiosRequestAdapter(), timeout: 5000, cacheFor: null,