This commit is contained in:
oneao committed 2025-11-12 17:31:12 +08:00
1 parent b8a6b15355
commit 95d645f572
13 files changed
+659 -62

No files matched your search

+6 -1
View File
@@ -19,6 +19,8 @@
"@react-native-segmented-control/segmented-control": "2.5.7", "@react-native-segmented-control/segmented-control": "2.5.7",
"alova": "^3.3.4", "alova": "^3.3.4",
"axios": "^1.13.2", "axios": "^1.13.2",
"big.js": "^7.0.1",
"dayjs": "^1.11.19",
"expo": "~54.0.20", "expo": "~54.0.20",
"expo-blur": "~15.0.7", "expo-blur": "~15.0.7",
"expo-constants": "~18.0.10", "expo-constants": "~18.0.10",
@@ -32,16 +34,19 @@
"nativewind": "^4.2.1", "nativewind": "^4.2.1",
"react": "19.1.0", "react": "19.1.0",
"react-native": "0.81.5", "react-native": "0.81.5",
"react-native-calendars": "^1.1313.0",
"react-native-dates-picker": "^0.2.0",
"react-native-gesture-handler": "~2.28.0", "react-native-gesture-handler": "~2.28.0",
"react-native-reanimated": "~4.1.3", "react-native-reanimated": "~4.1.3",
"react-native-safe-area-context": "~5.6.1", "react-native-safe-area-context": "~5.6.1",
"react-native-screens": "~4.16.0", "react-native-screens": "~4.16.0",
"react-native-segmented-control-2": "^2.1.1",
"react-native-svg": "15.12.0", "react-native-svg": "15.12.0",
"react-native-ui-datepicker": "^3.1.2",
"zustand": "^5.0.8" "zustand": "^5.0.8"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^6.2.0", "@antfu/eslint-config": "^6.2.0",
"@types/big.js": "^6.2.2",
"@types/react": "~19.1.0", "@types/react": "~19.1.0",
"babel-plugin-module-resolver": "^5.0.2", "babel-plugin-module-resolver": "^5.0.2",
"eslint": "^9.38.0", "eslint": "^9.38.0",
+156 -14
View File
@@ -35,6 +35,12 @@ importers:
axios: axios:
specifier: ^1.13.2 specifier: ^1.13.2
version: 1.13.2 version: 1.13.2
big.js:
specifier: ^7.0.1
version: 7.0.1
dayjs:
specifier: ^1.11.19
version: 1.11.19
expo: expo:
specifier: ~54.0.20 specifier: ~54.0.20
version: 54.0.21(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 54.0.21(@babel/core@7.28.5)(@expo/metro-runtime@6.1.2)(expo-router@6.0.14)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
@@ -74,6 +80,12 @@ importers:
react-native: react-native:
specifier: 0.81.5 specifier: 0.81.5
version: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) version: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
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-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: react-native-gesture-handler:
specifier: ~2.28.0 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) 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)
@@ -86,12 +98,12 @@ importers:
react-native-screens: react-native-screens:
specifier: ~4.16.0 specifier: ~4.16.0
version: 4.16.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: 4.16.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-segmented-control-2:
specifier: ^2.1.1
version: 2.1.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-svg: react-native-svg:
specifier: 15.12.0 specifier: 15.12.0
version: 15.12.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: 15.12.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-ui-datepicker:
specifier: ^3.1.2
version: 3.1.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
zustand: zustand:
specifier: ^5.0.8 specifier: ^5.0.8
version: 5.0.8(@types/react@19.1.17)(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0)) version: 5.0.8(@types/react@19.1.17)(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0))
@@ -99,6 +111,9 @@ importers:
'@antfu/eslint-config': '@antfu/eslint-config':
specifier: ^6.2.0 specifier: ^6.2.0
version: 6.2.0(@vue/compiler-sfc@3.5.22)(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3) version: 6.2.0(@vue/compiler-sfc@3.5.22)(eslint@9.39.0(jiti@1.21.7))(typescript@5.9.3)
'@types/big.js':
specifier: ^6.2.2
version: 6.2.2
'@types/react': '@types/react':
specifier: ~19.1.0 specifier: ~19.1.0
version: 19.1.17 version: 19.1.17
@@ -1997,6 +2012,9 @@ packages:
'@types/babel__traverse@7.28.0': '@types/babel__traverse@7.28.0':
resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
'@types/big.js@6.2.2':
resolution: {integrity: sha512-e2cOW9YlVzFY2iScnGBBkplKsrn2CsObHQ2Hiw4V1sSyiGbgWL8IyqE3zFi1Pt5o1pdAtYkDAIsF3KKUPjdzaA==}
'@types/debug@4.1.12': '@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
@@ -2343,6 +2361,9 @@ packages:
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
big.js@7.0.1:
resolution: {integrity: sha512-iFgV784tD8kq4ccF1xtNMZnXeZzVuXWWM+ERFzKQjv+A5G9HC8CY3DuV45vgzFFcW+u2tIvmF95+AzWgs6BjCg==}
binary-extensions@2.3.0: binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -2605,6 +2626,9 @@ packages:
csstype@3.1.3: csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
dayjs@1.11.19:
resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==}
debug@2.6.9: debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies: peerDependencies:
@@ -3543,6 +3567,9 @@ packages:
jackspeak@3.4.3: jackspeak@3.4.3:
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
jalali-plugin-dayjs@1.1.4:
resolution: {integrity: sha512-d62QGMTufGQ1TSov4a85gBU58PA8aL6wVQs9BnC3+d/VA+v4Sq0OqM3o6RoY+/VZjliYJroGIPwlSVf7uLnZ3w==}
jest-environment-node@29.7.0: jest-environment-node@29.7.0:
resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -3719,48 +3746,56 @@ packages:
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-arm64-gnu@1.30.2: lightningcss-linux-arm64-gnu@1.30.2:
resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.27.0: lightningcss-linux-arm64-musl@1.27.0:
resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==} resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-linux-arm64-musl@1.30.2: lightningcss-linux-arm64-musl@1.30.2:
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.27.0: lightningcss-linux-x64-gnu@1.27.0:
resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==} resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-x64-gnu@1.30.2: lightningcss-linux-x64-gnu@1.30.2:
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.27.0: lightningcss-linux-x64-musl@1.27.0:
resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==} resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-linux-x64-musl@1.30.2: lightningcss-linux-x64-musl@1.30.2:
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
engines: {node: '>= 12.0.0'} engines: {node: '>= 12.0.0'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.27.0: lightningcss-win32-arm64-msvc@1.27.0:
resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==} resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==}
@@ -4191,6 +4226,9 @@ packages:
mlly@1.8.0: mlly@1.8.0:
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
moment@2.30.1:
resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
ms@2.0.0: ms@2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
@@ -4523,6 +4561,9 @@ packages:
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
proxy-from-env@1.1.0: proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
@@ -4590,6 +4631,10 @@ packages:
react-is@19.2.0: react-is@19.2.0:
resolution: {integrity: sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==} resolution: {integrity: sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==}
react-native-calendars@1.1313.0:
resolution: {integrity: sha512-YQ7Vg57rBRVymolamYDTxZ0lPOELTDHQbTukTWdxR47aRBYJwKI6ocRbwcY5gYgyDwNgJS4uLGu5AvmYS74LYQ==}
engines: {node: '>=18'}
react-native-css-interop@0.2.1: react-native-css-interop@0.2.1:
resolution: {integrity: sha512-B88f5rIymJXmy1sNC/MhTkb3xxBej1KkuAt7TiT9iM7oXz3RM8Bn+7GUrfR02TvSgKm4cg2XiSuLEKYfKwNsjA==} resolution: {integrity: sha512-B88f5rIymJXmy1sNC/MhTkb3xxBej1KkuAt7TiT9iM7oXz3RM8Bn+7GUrfR02TvSgKm4cg2XiSuLEKYfKwNsjA==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -4606,6 +4651,13 @@ packages:
react-native-svg: react-native-svg:
optional: true optional: true
react-native-dates-picker@0.2.0:
resolution: {integrity: sha512-dO7HGami3fhKa/WVtd5jj0xfekbNJZzka++4+0pBUW8br2/t9YzyJ7DYPcZ7vGdRy6bw/qkBG6EASRq8DJP/5Q==}
engines: {node: '>= 16.0.0'}
peerDependencies:
react: '>=17.0.0'
react-native: '*'
react-native-gesture-handler@2.28.0: react-native-gesture-handler@2.28.0:
resolution: {integrity: sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==} resolution: {integrity: sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==}
peerDependencies: peerDependencies:
@@ -4634,6 +4686,12 @@ packages:
react-native: '*' react-native: '*'
react-native-worklets: '>=0.5.0' react-native-worklets: '>=0.5.0'
react-native-safe-area-context@4.5.0:
resolution: {integrity: sha512-0WORnk9SkREGUg2V7jHZbuN5x4vcxj/1B0QOcXJjdYWrzZHgLcUzYWWIUecUPJh747Mwjt/42RZDOaFn3L8kPQ==}
peerDependencies:
react: '*'
react-native: '*'
react-native-safe-area-context@5.6.1: react-native-safe-area-context@5.6.1:
resolution: {integrity: sha512-/wJE58HLEAkATzhhX1xSr+fostLsK8Q97EfpfMDKo8jlOc1QKESSX/FQrhk7HhQH/2uSaox4Y86sNaI02kteiA==} resolution: {integrity: sha512-/wJE58HLEAkATzhhX1xSr+fostLsK8Q97EfpfMDKo8jlOc1QKESSX/FQrhk7HhQH/2uSaox4Y86sNaI02kteiA==}
peerDependencies: peerDependencies:
@@ -4646,18 +4704,22 @@ packages:
react: '*' react: '*'
react-native: '*' react-native: '*'
react-native-segmented-control-2@2.1.1:
resolution: {integrity: sha512-qtDM4KhPMb/V3R6vVGWkhPVmUNLu+Vt+ypuYbsErFTCXLKMTmYfT+xH1rtvXn9cfzBM+lzjTiI5ij3hgs9/Tug==}
peerDependencies:
react: '>=17 || >=18'
react-native: '>=0.71'
react-native-svg@15.12.0: react-native-svg@15.12.0:
resolution: {integrity: sha512-iE25PxIJ6V0C6krReLquVw6R0QTsRTmEQc4K2Co3P6zsimU/jltcDBKYDy1h/5j9S/fqmMeXnpM+9LEWKJKI6A==} resolution: {integrity: sha512-iE25PxIJ6V0C6krReLquVw6R0QTsRTmEQc4K2Co3P6zsimU/jltcDBKYDy1h/5j9S/fqmMeXnpM+9LEWKJKI6A==}
peerDependencies: peerDependencies:
react: '*' react: '*'
react-native: '*' react-native: '*'
react-native-swipe-gestures@1.0.5:
resolution: {integrity: sha512-Ns7Bn9H/Tyw278+5SQx9oAblDZ7JixyzeOczcBK8dipQk2pD7Djkcfnf1nB/8RErAmMLL9iXgW0QHqiII8AhKw==}
react-native-ui-datepicker@3.1.2:
resolution: {integrity: sha512-1yukCKMLUuVb5daYOgb4mLZqpynZ6GMQyNF2NPwpiDB5F2D/NGpeOmoYb7qFwDrTNwr+m4IemNUa0TlYIFktlg==}
engines: {node: '>= 18'}
peerDependencies:
react: '*'
react-native: '*'
react-native-web@0.21.2: react-native-web@0.21.2:
resolution: {integrity: sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==} resolution: {integrity: sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==}
peerDependencies: peerDependencies:
@@ -4732,6 +4794,12 @@ packages:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'} engines: {node: '>=8.10.0'}
recyclerlistview@4.2.3:
resolution: {integrity: sha512-STR/wj/FyT8EMsBzzhZ1l2goYirMkIgfV3gYEPxI3Kf3lOnu6f7Dryhyw7/IkQrgX5xtTcDrZMqytvteH9rL3g==}
peerDependencies:
react: '>= 15.2.1'
react-native: '>= 0.30.0'
refa@0.12.1: refa@0.12.1:
resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
@@ -5061,6 +5129,9 @@ packages:
tailwind-merge@1.14.0: tailwind-merge@1.14.0:
resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==} resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==}
tailwind-merge@3.4.0:
resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==}
tailwind-variants@0.1.20: tailwind-variants@0.1.20:
resolution: {integrity: sha512-AMh7x313t/V+eTySKB0Dal08RHY7ggYK0MSn/ad8wKWOrDUIzyiWNayRUm2PIJ4VRkvRnfNuyRuKbLV3EN+ewQ==} resolution: {integrity: sha512-AMh7x313t/V+eTySKB0Dal08RHY7ggYK0MSn/ad8wKWOrDUIzyiWNayRUm2PIJ4VRkvRnfNuyRuKbLV3EN+ewQ==}
engines: {node: '>=16.x', pnpm: '>=7.x'} engines: {node: '>=16.x', pnpm: '>=7.x'}
@@ -5150,6 +5221,9 @@ packages:
ts-interface-checker@0.1.13: ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
ts-object-utils@0.0.5:
resolution: {integrity: sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA==}
tslib@1.14.1: tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
@@ -5396,6 +5470,9 @@ packages:
resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==} resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
xdate@0.8.3:
resolution: {integrity: sha512-1NhJWPJwN+VjbkACT9XHbQK4o6exeSVtS2CxhMPwUE7xQakoEFTlwra9YcqV/uHQVyeEUYoYC46VGDJ+etnIiw==}
xml-name-validator@4.0.0: xml-name-validator@4.0.0:
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -8179,6 +8256,8 @@ snapshots:
dependencies: dependencies:
'@babel/types': 7.28.5 '@babel/types': 7.28.5
'@types/big.js@6.2.2': {}
'@types/debug@4.1.12': '@types/debug@4.1.12':
dependencies: dependencies:
'@types/ms': 2.1.0 '@types/ms': 2.1.0
@@ -8623,6 +8702,8 @@ snapshots:
big-integer@1.6.52: {} big-integer@1.6.52: {}
big.js@7.0.1: {}
binary-extensions@2.3.0: {} binary-extensions@2.3.0: {}
boolbase@1.0.0: {} boolbase@1.0.0: {}
@@ -8891,6 +8972,8 @@ snapshots:
csstype@3.1.3: {} csstype@3.1.3: {}
dayjs@1.11.19: {}
debug@2.6.9: debug@2.6.9:
dependencies: dependencies:
ms: 2.0.0 ms: 2.0.0
@@ -9885,6 +9968,8 @@ snapshots:
optionalDependencies: optionalDependencies:
'@pkgjs/parseargs': 0.11.0 '@pkgjs/parseargs': 0.11.0
jalali-plugin-dayjs@1.1.4: {}
jest-environment-node@29.7.0: jest-environment-node@29.7.0:
dependencies: dependencies:
'@jest/environment': 29.7.0 '@jest/environment': 29.7.0
@@ -10913,6 +10998,9 @@ snapshots:
pkg-types: 1.3.1 pkg-types: 1.3.1
ufo: 1.6.1 ufo: 1.6.1
moment@2.30.1:
optional: true
ms@2.0.0: {} ms@2.0.0: {}
ms@2.1.3: {} ms@2.1.3: {}
@@ -11209,6 +11297,12 @@ snapshots:
kleur: 3.0.3 kleur: 3.0.3
sisteransi: 1.0.5 sisteransi: 1.0.5
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
object-assign: 4.1.1
react-is: 16.13.1
proxy-from-env@1.1.0: {} proxy-from-env@1.1.0: {}
punycode@2.3.1: {} punycode@2.3.1: {}
@@ -11313,6 +11407,22 @@ snapshots:
react-is@19.2.0: {} react-is@19.2.0: {}
react-native-calendars@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):
dependencies:
hoist-non-react-statics: 3.3.2
lodash: 4.17.21
memoize-one: 5.2.1
prop-types: 15.8.1
react-native-safe-area-context: 4.5.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-swipe-gestures: 1.0.5
recyclerlistview: 4.2.3(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
xdate: 0.8.3
optionalDependencies:
moment: 2.30.1
transitivePeerDependencies:
- react
- react-native
react-native-css-interop@0.2.1(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-safe-area-context@5.6.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-svg@15.12.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)(tailwindcss@3.4.18(yaml@2.8.1)): react-native-css-interop@0.2.1(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-safe-area-context@5.6.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-svg@15.12.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)(tailwindcss@3.4.18(yaml@2.8.1)):
dependencies: dependencies:
'@babel/helper-module-imports': 7.27.1 '@babel/helper-module-imports': 7.27.1
@@ -11331,6 +11441,12 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
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
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-gesture-handler@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-gesture-handler@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):
dependencies: dependencies:
'@egjs/hammerjs': 2.0.17 '@egjs/hammerjs': 2.0.17
@@ -11368,6 +11484,11 @@ snapshots:
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-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)
semver: 7.7.2 semver: 7.7.2
react-native-safe-area-context@4.5.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-safe-area-context@5.6.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-safe-area-context@5.6.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: dependencies:
react: 19.1.0 react: 19.1.0
@@ -11381,11 +11502,6 @@ snapshots:
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-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)
warn-once: 0.1.1 warn-once: 0.1.1
react-native-segmented-control-2@2.1.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-svg@15.12.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-svg@15.12.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:
css-select: 5.2.2 css-select: 5.2.2
@@ -11394,6 +11510,18 @@ snapshots:
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
warn-once: 0.1.1 warn-once: 0.1.1
react-native-swipe-gestures@1.0.5: {}
react-native-ui-datepicker@3.1.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies:
clsx: 2.1.1
dayjs: 1.11.19
jalali-plugin-dayjs: 1.1.4
lodash: 4.17.21
react: 19.1.0
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
tailwind-merge: 3.4.0
react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0): react-native-web@0.21.2(react-dom@19.2.0(react@19.1.0))(react@19.1.0):
dependencies: dependencies:
'@babel/runtime': 7.28.4 '@babel/runtime': 7.28.4
@@ -11544,6 +11672,14 @@ snapshots:
dependencies: dependencies:
picomatch: 2.3.1 picomatch: 2.3.1
recyclerlistview@4.2.3(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies:
lodash.debounce: 4.0.8
prop-types: 15.8.1
react: 19.1.0
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
ts-object-utils: 0.0.5
refa@0.12.1: refa@0.12.1:
dependencies: dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
@@ -11849,6 +11985,8 @@ snapshots:
tailwind-merge@1.14.0: {} tailwind-merge@1.14.0: {}
tailwind-merge@3.4.0: {}
tailwind-variants@0.1.20(tailwindcss@3.4.18(yaml@2.8.1)): tailwind-variants@0.1.20(tailwindcss@3.4.18(yaml@2.8.1)):
dependencies: dependencies:
tailwind-merge: 1.14.0 tailwind-merge: 1.14.0
@@ -11959,6 +12097,8 @@ snapshots:
ts-interface-checker@0.1.13: {} ts-interface-checker@0.1.13: {}
ts-object-utils@0.0.5: {}
tslib@1.14.1: {} tslib@1.14.1: {}
tslib@2.8.1: {} tslib@2.8.1: {}
@@ -12154,6 +12294,8 @@ snapshots:
simple-plist: 1.3.1 simple-plist: 1.3.1
uuid: 7.0.3 uuid: 7.0.3
xdate@0.8.3: {}
xml-name-validator@4.0.0: {} xml-name-validator@4.0.0: {}
xml2js@0.4.23: xml2js@0.4.23:
@@ -1,28 +1,19 @@
import { ScrollView, Text } from 'react-native' import type { DateType } from 'react-native-ui-datepicker'
import { AButton } from '@/components/common/ao' import { useState } from 'react'
import { useUserStore } from '@/store/user' import DateTimePicker, { useDefaultStyles } from 'react-native-ui-datepicker'
export default function Chat() { export default function Calendar() {
const userStore = useUserStore() const defaultStyles = useDefaultStyles()
const [selected, setSelected] = useState<DateType>()
return ( return (
<ScrollView contentContainerStyle={{ padding: 16, marginTop: 22 }}> <DateTimePicker
<AButton mode="single"
onPress={() => { date={selected}
userStore.setUserInfo({ onChange={({ date }) => setSelected(date)}
...(userStore.userInfo as any), styles={defaultStyles}
token: `test-token-${Date.now()}`, className="mt-22"
}) />
}}
>
测试
</AButton>
<Text style={{ marginTop: 12 }}>
当前 token:
{' '}
{userStore.userInfo?.token ?? '(无)'}
</Text>
</ScrollView>
) )
} }
@@ -0,0 +1,68 @@
import { Pressable, StyleSheet, Text, View } from 'react-native'
const Locales = ['zh-cn', 'en', 'de', 'es']
interface Props {
locale: string
setLocale: (locale: string) => void
mainColor?: string
activeTextColor?: string
}
export default function LocaleSelector({
locale,
setLocale,
mainColor,
activeTextColor,
}: Props) {
return (
<View style={styles.localeContainer}>
<Text style={{ marginRight: 8 }}>Locale:</Text>
{Locales.map((item, index) => (
<Pressable
key={index}
style={[
styles.localeButton,
item === locale && {
backgroundColor: mainColor,
},
]}
onPress={() => setLocale(item)}
accessibilityRole="button"
accessibilityLabel={item.toUpperCase()}
>
<Text
style={[
styles.localeButtonText,
item === locale && {
fontWeight: 'bold',
color: activeTextColor,
},
]}
>
{item.split('-')[0]?.toUpperCase()}
</Text>
</Pressable>
))}
</View>
)
}
const styles = StyleSheet.create({
localeContainer: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 20,
},
localeButton: {
alignItems: 'center',
justifyContent: 'center',
width: 36,
height: 36,
borderRadius: 36,
margin: 2,
},
localeButtonText: {
fontSize: 15,
},
})
@@ -0,0 +1,54 @@
import { Pressable, StyleSheet, View } from 'react-native'
export interface ITheme {
mainColor: string
activeTextColor: string
}
interface Props {
themes: ITheme[]
setTheme: (theme: ITheme) => void
}
export default function ThemeSelector({ themes = [], setTheme }: Props) {
return (
<View style={styles.themeContainer}>
{themes.map((item, index) => (
<Pressable
key={index}
style={[
styles.themeButton,
{
borderColor: item.activeTextColor,
backgroundColor: item.mainColor,
},
]}
onPress={() => setTheme(item)}
accessibilityRole="button"
accessibilityLabel="Set Active Theme"
/>
))}
</View>
)
}
const styles = StyleSheet.create({
themeContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
marginBottom: 10,
width: 330,
},
themeButton: {
borderWidth: 4,
width: 32,
height: 32,
borderRadius: 32,
margin: 5,
shadowRadius: 20,
shadowColor: '#000',
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 0 },
},
})
@@ -1,17 +1,17 @@
import type { MoneyCategoryResult } from '@/request/api/money' import type { MoneyCategoryResult } from '@/request/api/money'
import type { MoneyCategory } from '@/types/money' import type { MoneyCategory } from '@/types/money'
import { DeleteIcon } from 'lucide-react-native' import Big from 'big.js'
import dayjs from 'dayjs'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { Pressable, Text, View } from 'react-native' import { Pressable, StyleSheet, Text, View } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context' import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { AInput } from '@/components/common/ao' import { AInput, LucideIcon } from '@/components/common/ao'
import SegmentedTabs from '@/components/common/ao/SegmentedTabs' import SegmentedTabs from '@/components/common/ao/SegmentedTabs'
import { import {
Drawer, Drawer,
DrawerBackdrop, DrawerBackdrop,
DrawerBody, DrawerBody,
DrawerContent, DrawerContent,
DrawerFooter,
DrawerHeader, DrawerHeader,
} from '@/components/ui/drawer' } from '@/components/ui/drawer'
import { Grid, GridItem } from '@/components/ui/grid' import { Grid, GridItem } from '@/components/ui/grid'
@@ -31,24 +31,24 @@ const keys: KeydownItem[] = [
{ key: '1', content: <Text className="text-2xl">1</Text> }, { key: '1', content: <Text className="text-2xl">1</Text> },
{ key: '2', content: <Text className="text-2xl">2</Text> }, { key: '2', content: <Text className="text-2xl">2</Text> },
{ key: '3', content: <Text className="text-2xl">3</Text> }, { key: '3', content: <Text className="text-2xl">3</Text> },
{ key: 'del', content: <DeleteIcon strokeWidth={1} /> }, { key: 'del', content: <LucideIcon icon="Delete" size={22} strokeWidth={1.5} clickable={false} /> },
{ key: '4', content: <Text className="text-2xl">4</Text> }, { key: '4', content: <Text className="text-2xl">4</Text> },
{ key: '5', content: <Text className="text-2xl">5</Text> }, { key: '5', content: <Text className="text-2xl">5</Text> },
{ key: '6', content: <Text className="text-2xl">6</Text> }, { key: '6', content: <Text className="text-2xl">6</Text> },
{ key: '+', content: <Text className="text-2xl">+</Text> }, { key: '+', content: <LucideIcon icon="Plus" size={22} strokeWidth={1.5} clickable={false} /> },
{ key: '7', content: <Text className="text-2xl">7</Text> }, { key: '7', content: <Text className="text-2xl">7</Text> },
{ key: '8', content: <Text className="text-2xl">8</Text> }, { key: '8', content: <Text className="text-2xl">8</Text> },
{ key: '9', content: <Text className="text-2xl">9</Text> }, { key: '9', content: <Text className="text-2xl">9</Text> },
{ key: '-', content: <Text className="text-2xl">-</Text> }, { key: '-', content: <LucideIcon icon="Minus" size={22} strokeWidth={1.5} clickable={false} /> },
{ key: 'clear', content: ( { key: 'repeat', content: (
<View className="w-full h-full flex items-center justify-center"> <View className="w-full h-full flex items-center justify-center">
<Text className="text-2xl text-red-500">AC</Text> <Text className="text-xl text-gray-600">再记</Text>
</View> </View>
) }, ) },
{ key: '0', content: <Text className="text-2xl">0</Text> }, { key: '0', content: <Text className="text-2xl">0</Text> },
{ key: '.', content: <Text>.</Text> }, { key: '.', content: <LucideIcon icon="Dot" size={22} strokeWidth={1.5} clickable={false} /> },
{ key: '/', content: ( { key: '/', content: (
<View className="w-full h-full bg-amber-100 flex items-center justify-center"> <View className="w-full h-full flex items-center justify-center">
<Text className="text-2xl">完成</Text> <Text className="text-2xl">完成</Text>
</View> </View>
) }, ) },
@@ -62,6 +62,9 @@ export default function AddMoneyDrawer({
const [selectedIndex, setSelectedIndex] = useState(0) const [selectedIndex, setSelectedIndex] = useState(0)
const [selectedCategoryId, setSelectedCategoryId] = useState<number | null>(null) const [selectedCategoryId, setSelectedCategoryId] = useState<number | null>(null)
const [showKeydown, setShowKeydown] = useState(false) const [showKeydown, setShowKeydown] = useState(false)
const [keydownInput, setKeydownInput] = useState<string>('')
const [result, setResult] = useState('0')
const [date, setDate] = useState(dayjs())
const [categories, setCategories] = useState<MoneyCategoryResult>({ const [categories, setCategories] = useState<MoneyCategoryResult>({
income: [], income: [],
@@ -79,7 +82,7 @@ export default function AddMoneyDrawer({
try { try {
const res = await getMoneyCategoryApi() const res = await getMoneyCategoryApi()
if (res.isSuccess) { if (res.isSuccess) {
setCategories(res.data) // setCategories(res.data)
} }
} }
catch (err) { catch (err) {
@@ -90,17 +93,161 @@ export default function AddMoneyDrawer({
} }
}, [isOpen]) }, [isOpen])
const handlePress = (key: string | number, idx: number) => { function onMainDrawerClose() {
console.log('点击了格子 key:', key, '索引:', idx) setShowKeydown(false)
onClose()
} }
const handlePress = (key: string | number) => {
setKeydownInput((prev) => {
let newInput = prev
if (key === 'del') {
newInput = prev.slice(0, -1)
}
else if (key === '/') {
// 完成操作,可以在这里提交或关闭键盘
return prev
}
else {
const keyStr = key.toString()
// 检查是否要输入运算符(+ 或 -)
if (keyStr === '+' || keyStr === '-') {
// 获取最后一个字符
const lastChar = prev.slice(-1)
// 如果最后一个字符已经是运算符,则替换而不是追加
if (lastChar === '+' || lastChar === '-') {
newInput = prev.slice(0, -1) + keyStr
}
else {
newInput = prev + keyStr
}
}
// 检查是否要输入小数点(.)
else if (keyStr === '.') {
// 检查当前数字是否已经包含小数点
const parts = prev.split(/[+-]/)
const currentNumber = parts[parts.length - 1]
// 如果当前数字中还没有小数点,可以添加
if (!currentNumber.includes('.')) {
// 检查当前数字的小数位数(应该是0,因为还没有小数点)
if (currentNumber === '' || /[+-]/.test(prev.slice(-1))) {
newInput = `${prev}0.`
}
else {
newInput = `${prev}.`
}
}
else {
// 已经有小数点了,不重复添加
newInput = prev
}
}
// 处理数字输入
else if (/^\d$/.test(keyStr)) {
// 检查当前数字的小数位数
const parts = prev.split(/[+-]/)
const currentNumber = parts[parts.length - 1]
// 如果当前数字包含小数点,检查小数位数
if (currentNumber.includes('.')) {
const decimalParts = currentNumber.split('.')
// 如果小数部分已经达到2位,不允许继续输入
if (decimalParts.length > 1 && decimalParts[1].length >= 2) {
newInput = prev // 不改变输入
}
else {
newInput = prev + keyStr
}
}
else {
// 没有小数点,正常输入数字
newInput = prev + keyStr
}
}
else {
// 对于其他字符,正常追加
newInput = prev + keyStr
}
}
// 计算结果
try {
const computed = calculateWithBig(newInput)
setResult(computed)
}
catch (e) {
setResult('0')
}
return newInput
})
}
function calculateWithBig(expression: string): string {
if (!expression.trim())
return '0'
// 移除表达式末尾的运算符(+或-),避免不完整的表达式
let cleanExpression = expression.trim()
const lastChar = cleanExpression.slice(-1)
if (lastChar === '+' || lastChar === '-') {
cleanExpression = cleanExpression.slice(0, -1)
}
if (!cleanExpression)
return '0'
try {
// 使用更智能的解析方式,支持基本的加减运算
const numbers = cleanExpression.split(/[+-]/).filter(Boolean)
const operators = cleanExpression.split(/[^+-]/).filter(Boolean)
if (numbers.length === 0)
return '0'
let result = new Big(numbers[0])
for (let i = 0; i < operators.length; i++) {
const operator = operators[i]
const nextNumber = new Big(numbers[i + 1])
if (operator === '+') {
result = result.plus(nextNumber)
}
else if (operator === '-') {
result = result.minus(nextNumber)
}
}
// 限制结果为最多两位小数
return result.toFixed(2)
}
catch (error) {
// 如果解析失败,尝试只计算数字部分
const tokens = expression.match(/[+-]?\d+(\.\d+)?/g)
if (!tokens || tokens.length === 0)
return '0'
let total = new Big(0)
tokens.forEach((token) => {
total = total.plus(new Big(token))
})
// 限制结果为最多两位小数
return total.toFixed(2)
}
}
return ( return (
<> <>
<Drawer <Drawer
isOpen={isOpen} isOpen={isOpen}
size="full" size="full"
anchor="bottom" anchor="bottom"
onClose={onClose} onClose={onMainDrawerClose}
> >
<DrawerBackdrop /> <DrawerBackdrop />
<DrawerContent style={{ padding: 0, paddingLeft: 16, paddingRight: 16 }}> <DrawerContent style={{ padding: 0, paddingLeft: 16, paddingRight: 16 }}>
@@ -116,7 +263,7 @@ export default function AddMoneyDrawer({
style={{ width: 180 }} style={{ width: 180 }}
className="mx-auto" className="mx-auto"
/> />
<Pressable onPress={onClose}> <Pressable onPress={onMainDrawerClose}>
<Text className="text-gray-500 font-medium">取消</Text> <Text className="text-gray-500 font-medium">取消</Text>
</Pressable> </Pressable>
</DrawerHeader> </DrawerHeader>
@@ -167,6 +314,7 @@ export default function AddMoneyDrawer({
isOpen={showKeydown} isOpen={showKeydown}
size="md" size="md"
anchor="bottom" anchor="bottom"
onClose={() => setShowKeydown(false)}
> >
<DrawerContent <DrawerContent
style={{ style={{
@@ -180,7 +328,21 @@ export default function AddMoneyDrawer({
> >
<View className="flex-1"> <View className="flex-1">
<View className="p-4"> <View className="p-4">
<Text className="text-3xl text-blue-700 text-right">0.00</Text> <View className="flex flex-row items-center justify-between">
<Pressable
className="flex flex-row items-center gap-1.5 px-2 py-1.5 rounded-md bg-gray-50 active:opacity-70"
>
<LucideIcon icon="Calendar" size={16} color="#60a5fa" />
<Text className="text-gray-600 text-sm">2024/11/05</Text>
<LucideIcon icon="ChevronDown" size={12} color="#aaa" />
</Pressable>
<Text className="text-3xl text-blue-700 text-right">{result}</Text>
</View>
<View className="mt-1">
<Text className="text-gray-400 text-right">{keydownInput}</Text>
</View>
<AInput <AInput
value="" value=""
placeholder="备注" placeholder="备注"
@@ -200,7 +362,7 @@ export default function AddMoneyDrawer({
return ( return (
<Pressable <Pressable
key={item.key} key={item.key}
onPress={() => handlePress(item.key, idx)} onPress={() => handlePress(item.key)}
style={{ style={{
width: '25%', width: '25%',
height: '25%', height: '25%',
@@ -213,7 +375,22 @@ export default function AddMoneyDrawer({
borderColor: '#ddd', borderColor: '#ddd',
}} }}
> >
{({ pressed }) => {
const defaultBg = item.key === '/' ? '#e6d7b8' : '#fff'
const pressedBg = item.key === '/' ? '#f5e9d4' : '#f2f2f2'
return (
<>
<View
style={{
...StyleSheet.absoluteFillObject,
backgroundColor: pressed ? pressedBg : defaultBg,
}}
/>
{item.content} {item.content}
</>
)
}}
</Pressable> </Pressable>
) )
})} })}
@@ -223,6 +400,7 @@ export default function AddMoneyDrawer({
</View> </View>
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
</> </>
) )
} }
@@ -10,6 +10,7 @@ interface LucideIconProps {
strokeWidth?: number strokeWidth?: number
onPress?: (event: GestureResponderEvent) => void onPress?: (event: GestureResponderEvent) => void
style?: ViewStyle style?: ViewStyle
clickable?: boolean // 新增参数,是否可点击,默认 true
} }
export default function LucideIcon({ export default function LucideIcon({
@@ -19,12 +20,18 @@ export default function LucideIcon({
strokeWidth = 2, strokeWidth = 2,
onPress, onPress,
style, style,
clickable = true,
}: LucideIconProps) { }: LucideIconProps) {
const IconComponent = icons[icon] const IconComponent = icons[icon]
if (!IconComponent) if (!IconComponent)
return null return null
if (!clickable) {
return <IconComponent size={size} color={color} strokeWidth={strokeWidth} style={style} />
}
// clickable 为 true,包 Pressable
return ( return (
<Pressable onPress={onPress} style={style}> <Pressable onPress={onPress} style={style}>
<IconComponent size={size} color={color} strokeWidth={strokeWidth} /> <IconComponent size={size} color={color} strokeWidth={strokeWidth} />
@@ -11,3 +11,34 @@ export interface MoneyCategoryResult {
export function getMoneyCategoryApi() { export function getMoneyCategoryApi() {
return alovaInstance.Get<ResponseData<MoneyCategoryResult>>(`${API_PREFIX}/category`) return alovaInstance.Get<ResponseData<MoneyCategoryResult>>(`${API_PREFIX}/category`)
} }
interface InsertMoneyRecordParams {
category_id: number
amount: string
record_time: string
remark: string
}
export function insertMoneyRecordApi(params: InsertMoneyRecordParams) {
return alovaInstance.Post<ResponseData<MoneyCategory>>(`${API_PREFIX}/insert`, params)
}
interface UpdateMoneyRecordParams {
id: number
category_id: number
amount: string
record_time: string
remark: string
}
export function updateMoneyRecordApi(params: UpdateMoneyRecordParams) {
return alovaInstance.Post<ResponseData<any>>(`${API_PREFIX}/update`, params)
}
interface DeleteMoneyRecordParams {
id: number
}
export function deleteMoneyRecordApi(params: DeleteMoneyRecordParams) {
return alovaInstance.Post<ResponseData<any>>(`${API_PREFIX}/delete`, params)
}
@@ -30,11 +30,11 @@ function isWhiteListed(url: string) {
} }
const alovaInstance = createAlova({ const alovaInstance = createAlova({
baseURL: 'http://192.168.5.6:8085/app', // baseURL: 'http://192.168.5.6:8085/app',
// baseURL: 'http://192.168.1.136:8085/app', baseURL: 'http://192.168.1.136:8085/app',
requestAdapter: axiosRequestAdapter(), requestAdapter: axiosRequestAdapter(),
timeout: 5000, timeout: 5000,
cacheLogger: false, cacheFor: null,
responded: { responded: {
onSuccess: async (response, method: Method) => { onSuccess: async (response, method: Method) => {
const resData = response.data as ResponseData<any> const resData = response.data as ResponseData<any>
@@ -154,7 +154,6 @@ const alovaInstance = createAlova({
return Promise.reject(new Error('未登录')) return Promise.reject(new Error('未登录'))
} }
method.config.cacheFor = 0
method.config.headers.token = useUserStore.getState().userInfo?.token ?? '' method.config.headers.token = useUserStore.getState().userInfo?.token ?? ''
}, },
}) })
@@ -6,3 +6,13 @@ export interface MoneyCategory {
sort_number: number sort_number: number
type: number type: number
} }
export interface MoneyRecord {
id: number
category_id: number
user_id: number
amount: string
remark: string
record_time: string
create_time: string
}
+1
View File
@@ -21,6 +21,7 @@ require (
github.com/klauspost/compress v1.18.1 // indirect github.com/klauspost/compress v1.18.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect github.com/spf13/cast v1.10.0 // indirect
+2
View File
@@ -27,6 +27,8 @@ github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDc
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
@@ -7,12 +7,15 @@ import (
"base-go-v2/internal/utils/idgen" "base-go-v2/internal/utils/idgen"
"base-go-v2/internal/utils/mapx" "base-go-v2/internal/utils/mapx"
"fmt" "fmt"
"github.com/shopspring/decimal"
) )
func InitMoneyRouter(r *router.Router) { func InitMoneyRouter(r *router.Router) {
group := r.Group("money") group := r.Group("money")
group.GET("/category", getUserCategory) group.GET("/category", getUserCategory)
//group := r.Group("auth") group.POST("/insert", insertMoneyRecord)
group.POST("/update", updateMoneyRecord)
group.POST("/delete", deleteMoneyRecord)
} }
// InitDefaultCategories 初始化系统默认分类到用户分类表 // InitDefaultCategories 初始化系统默认分类到用户分类表
@@ -54,7 +57,6 @@ func InitDefaultCategories(userID int64) error {
} }
func getUserCategory(c *router.Context) error { func getUserCategory(c *router.Context) error {
fmt.Println("请求进入了====")
userId := c.GetUserID() userId := c.GetUserID()
// 查询当前用户的分类 // 查询当前用户的分类
@@ -80,3 +82,110 @@ func getUserCategory(c *router.Context) error {
return response.Success(c).Data(result).Send() return response.Success(c).Data(result).Send()
} }
func insertMoneyRecord(c *router.Context) error {
bodyData, err := c.GetBodyWithRequired("category_id", "amount", "record_time")
if err != nil {
return c.AddError(err)
}
categoryId := bodyData.GetInt64("category_id")
recordTime := bodyData.GetString("record_time")
amountStr := bodyData.GetString("amount")
remark := bodyData.GetString("remark")
amountDecimal, err := decimal.NewFromString(amountStr)
if err != nil {
return c.AddError(err)
}
newRecord := mapx.New().SetKV("id", idgen.NextId(),
"category_id", categoryId,
"user_id", c.GetUserID(),
"amount", amountDecimal,
"remark", remark,
"record_time", recordTime,
)
insertOne, err := db.InsertOne("money_record", newRecord)
if err != nil {
return response.Fail(c).Message("新增失败").Send()
}
if insertOne != 1 {
return response.Fail(c).Message("新增失败").Send()
}
return response.Success(c).Data(newRecord).Message("新增成功").Send()
}
func updateMoneyRecord(c *router.Context) error {
bodyData, err := c.GetBodyWithRequired("id")
if err != nil {
return c.AddError(err)
}
recordId := bodyData.GetInt64("id")
record, err := db.GetOne("money_record", "id", recordId)
if err != nil {
return c.AddError(err)
}
if record == nil {
return response.Fail(c).Message("该条账单不存在").Send()
}
categoryId := bodyData.GetInt64("category_id")
recordTime := bodyData.GetString("record_time")
amountStr := bodyData.GetString("amount")
remark := bodyData.GetString("remark")
updateRecord := mapx.New().SetKV("id", recordId)
if record.GetInt64("category_id") != categoryId {
updateRecord.SetKV("category_id", categoryId)
}
if record.GetString("record_time") != recordTime {
updateRecord.SetKV("record_time", recordTime)
}
if record.GetString("amount") != amountStr {
amountDecimal, err := decimal.NewFromString(amountStr)
if err != nil {
return c.AddError(err)
}
updateRecord.SetKV("amount", amountDecimal)
}
if record.GetString("remark") != remark {
updateRecord.SetKV("remark", remark)
}
updateOne, err := db.UpdateOne("money_record", "id", recordId, updateRecord)
if err != nil {
return c.AddError(err)
}
if updateOne != 1 {
return response.Fail(c).Message("更新失败").Send()
}
return response.Success(c).Message("更新成功").Send()
}
func deleteMoneyRecord(c *router.Context) error {
bodyData, err := c.GetBodyWithRequired("id")
if err != nil {
return c.AddError(err)
}
recordId := bodyData.GetInt64("id")
deleteOne, err := db.DeleteOne("money_record", "id", recordId)
if err != nil {
return c.AddError(err)
}
if deleteOne != 1 {
return response.Fail(c).Message("删除失败").Send()
}
return response.Success(c).Message("删除成功").Send()
}