u
This commit is contained in:
1 parent
18e9d94b77
commit
1f82f1dd1f
16 files changed
+1048
-297
No files matched your search
@@ -45,7 +45,7 @@
|
|||||||
"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-svg": "15.12.1",
|
"react-native-svg": "15.12.0",
|
||||||
"react-native-web": "^0.21.0",
|
"react-native-web": "^0.21.0",
|
||||||
"react-native-worklets": "0.5.1",
|
"react-native-worklets": "0.5.1",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.4.0",
|
||||||
|
|||||||
+37
-29
@@ -13,7 +13,7 @@ importers:
|
|||||||
version: 2.0.16(alova@3.3.4)(axios@1.13.2)
|
version: 2.0.16(alova@3.3.4)(axios@1.13.2)
|
||||||
'@gluestack-ui/core':
|
'@gluestack-ui/core':
|
||||||
specifier: ^3.0.12
|
specifier: ^3.0.12
|
||||||
version: 3.0.12(@gluestack-ui/utils@3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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-safe-area-context@5.6.2(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.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-web@0.21.2(react-dom@19.1.0(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: 3.0.12(@gluestack-ui/utils@3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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-safe-area-context@5.6.2(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-web@0.21.2(react-dom@19.1.0(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)
|
||||||
'@gluestack-ui/utils':
|
'@gluestack-ui/utils':
|
||||||
specifier: ^3.0.11
|
specifier: ^3.0.11
|
||||||
version: 3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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))
|
version: 3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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))
|
||||||
@@ -22,7 +22,7 @@ importers:
|
|||||||
version: 3.0.3
|
version: 3.0.3
|
||||||
'@legendapp/motion':
|
'@legendapp/motion':
|
||||||
specifier: ^2.4.0
|
specifier: ^2.4.0
|
||||||
version: 2.5.3(nativewind@4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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.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)(tailwindcss@3.4.18(yaml@2.8.1)))(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.4.0(nativewind@4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
'@react-native-async-storage/async-storage':
|
'@react-native-async-storage/async-storage':
|
||||||
specifier: 2.2.0
|
specifier: 2.2.0
|
||||||
version: 2.2.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))
|
version: 2.2.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))
|
||||||
@@ -76,13 +76,13 @@ importers:
|
|||||||
version: 3.0.8(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
version: 3.0.8(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
lucide-react-native:
|
lucide-react-native:
|
||||||
specifier: ^0.510.0
|
specifier: ^0.510.0
|
||||||
version: 0.510.0(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: 0.510.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)
|
||||||
moment:
|
moment:
|
||||||
specifier: ^2.30.1
|
specifier: ^2.30.1
|
||||||
version: 2.30.1
|
version: 2.30.1
|
||||||
nativewind:
|
nativewind:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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.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)(tailwindcss@3.4.18(yaml@2.8.1))
|
version: 4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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:
|
react:
|
||||||
specifier: 19.1.0
|
specifier: 19.1.0
|
||||||
version: 19.1.0
|
version: 19.1.0
|
||||||
@@ -94,7 +94,7 @@ importers:
|
|||||||
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-css-interop:
|
react-native-css-interop:
|
||||||
specifier: ^0.2.1
|
specifier: ^0.2.1
|
||||||
version: 0.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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.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)(tailwindcss@3.4.18(yaml@2.8.1))
|
version: 0.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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-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)
|
||||||
@@ -114,8 +114,8 @@ importers:
|
|||||||
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-svg:
|
react-native-svg:
|
||||||
specifier: 15.12.1
|
specifier: 15.12.0
|
||||||
version: 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)
|
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-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)
|
||||||
@@ -146,10 +146,10 @@ importers:
|
|||||||
version: 9.39.1(jiti@1.21.7)
|
version: 9.39.1(jiti@1.21.7)
|
||||||
react-native-iconfont-cli:
|
react-native-iconfont-cli:
|
||||||
specifier: ^2.2.4
|
specifier: ^2.2.4
|
||||||
version: 2.2.4(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: 2.2.4(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)
|
||||||
react-native-svg-transformer:
|
react-native-svg-transformer:
|
||||||
specifier: ^1.5.2
|
specifier: ^1.5.2
|
||||||
version: 1.5.2(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))(typescript@5.9.3)
|
version: 1.5.2(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))(typescript@5.9.3)
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.4.17
|
specifier: ^3.4.17
|
||||||
version: 3.4.18(yaml@2.8.1)
|
version: 3.4.18(yaml@2.8.1)
|
||||||
@@ -1074,10 +1074,10 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.31':
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||||
|
|
||||||
'@legendapp/motion@2.5.3':
|
'@legendapp/motion@2.4.0':
|
||||||
resolution: {integrity: sha512-IcNiStiK3qG5LaIPLC8fVV0BHIrkf7EY5HfOv3xbuMH0z4D945yaaEDafP5bboHf/uj9XRjTQHVTtZgwpMNlHw==}
|
resolution: {integrity: sha512-AAYpRLGvxGD5hIGl9sVHyoUufr66zoH82PuxYcKiPSMdCBI3jwZFWh6CuHjV1leRKVIRk2py1rSvIVabG8eqcw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
nativewind: '>=4.0.0'
|
nativewind: '*'
|
||||||
react: '>=16'
|
react: '>=16'
|
||||||
react-native: '*'
|
react-native: '*'
|
||||||
|
|
||||||
@@ -3902,48 +3902,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==}
|
||||||
@@ -4880,8 +4888,8 @@ packages:
|
|||||||
react-native: '>=0.59.0'
|
react-native: '>=0.59.0'
|
||||||
react-native-svg: '>=12.0.0'
|
react-native-svg: '>=12.0.0'
|
||||||
|
|
||||||
react-native-svg@15.12.1:
|
react-native-svg@15.12.0:
|
||||||
resolution: {integrity: sha512-vCuZJDf8a5aNC2dlMovEv4Z0jjEUET53lm/iILFnFewa15b4atjVxU6Wirm6O9y6dEsdjDZVD7Q3QM4T1wlI8g==}
|
resolution: {integrity: sha512-iE25PxIJ6V0C6krReLquVw6R0QTsRTmEQc4K2Co3P6zsimU/jltcDBKYDy1h/5j9S/fqmMeXnpM+9LEWKJKI6A==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: '*'
|
react: '*'
|
||||||
react-native: '*'
|
react-native: '*'
|
||||||
@@ -6834,13 +6842,13 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@gluestack-ui/core@3.0.12(@gluestack-ui/utils@3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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-safe-area-context@5.6.2(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.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-web@0.21.2(react-dom@19.1.0(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)':
|
'@gluestack-ui/core@3.0.12(@gluestack-ui/utils@3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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-safe-area-context@5.6.2(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-web@0.21.2(react-dom@19.1.0(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:
|
||||||
'@gluestack-ui/utils': 3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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))
|
'@gluestack-ui/utils': 3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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: 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-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.2(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.2(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.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-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
|
||||||
'@gluestack-ui/utils@3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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))':
|
'@gluestack-ui/utils@3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(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))':
|
||||||
@@ -6991,10 +6999,10 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
'@legendapp/motion@2.5.3(nativewind@4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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.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)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
|
'@legendapp/motion@2.4.0(nativewind@4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@legendapp/tools': 2.0.1(react@19.1.0)
|
'@legendapp/tools': 2.0.1(react@19.1.0)
|
||||||
nativewind: 4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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.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)(tailwindcss@3.4.18(yaml@2.8.1))
|
nativewind: 4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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: 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-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
|
||||||
|
|
||||||
@@ -10552,11 +10560,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
yallist: 3.1.1
|
yallist: 3.1.1
|
||||||
|
|
||||||
lucide-react-native@0.510.0(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):
|
lucide-react-native@0.510.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):
|
||||||
dependencies:
|
dependencies:
|
||||||
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-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
|
||||||
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-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)
|
||||||
|
|
||||||
magic-string@0.30.21:
|
magic-string@0.30.21:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -11317,11 +11325,11 @@ snapshots:
|
|||||||
|
|
||||||
nanoid@3.3.11: {}
|
nanoid@3.3.11: {}
|
||||||
|
|
||||||
nativewind@4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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.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)(tailwindcss@3.4.18(yaml@2.8.1)):
|
nativewind@4.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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:
|
||||||
comment-json: 4.4.1
|
comment-json: 4.4.1
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
react-native-css-interop: 0.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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.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)(tailwindcss@3.4.18(yaml@2.8.1))
|
react-native-css-interop: 0.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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))
|
||||||
tailwindcss: 3.4.18(yaml@2.8.1)
|
tailwindcss: 3.4.18(yaml@2.8.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- react
|
- react
|
||||||
@@ -11731,7 +11739,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
prop-types: 15.8.1
|
prop-types: 15.8.1
|
||||||
|
|
||||||
react-native-css-interop@0.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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.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)(tailwindcss@3.4.18(yaml@2.8.1)):
|
react-native-css-interop@0.2.1(react-native-reanimated@4.1.5(@babel/core@7.28.5)(react-native-worklets@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))(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.2(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
|
||||||
'@babel/traverse': 7.28.5
|
'@babel/traverse': 7.28.5
|
||||||
@@ -11745,7 +11753,7 @@ snapshots:
|
|||||||
tailwindcss: 3.4.18(yaml@2.8.1)
|
tailwindcss: 3.4.18(yaml@2.8.1)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
react-native-safe-area-context: 5.6.2(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.2(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.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)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -11757,7 +11765,7 @@ snapshots:
|
|||||||
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-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
|
||||||
|
|
||||||
react-native-iconfont-cli@2.2.4(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-iconfont-cli@2.2.4(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):
|
||||||
dependencies:
|
dependencies:
|
||||||
colors: 1.4.0
|
colors: 1.4.0
|
||||||
glob: 7.2.3
|
glob: 7.2.3
|
||||||
@@ -11767,7 +11775,7 @@ snapshots:
|
|||||||
mkdirp: 0.5.6
|
mkdirp: 0.5.6
|
||||||
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-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
|
||||||
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-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)
|
||||||
tslib: 1.14.1
|
tslib: 1.14.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -11812,19 +11820,19 @@ 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-svg-transformer@1.5.2(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))(typescript@5.9.3):
|
react-native-svg-transformer@1.5.2(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))(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@svgr/core': 8.1.0(typescript@5.9.3)
|
'@svgr/core': 8.1.0(typescript@5.9.3)
|
||||||
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))
|
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))
|
||||||
'@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3)
|
'@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3)
|
||||||
path-dirname: 1.0.2
|
path-dirname: 1.0.2
|
||||||
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)
|
||||||
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-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)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
- typescript
|
- typescript
|
||||||
|
|
||||||
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-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
|
||||||
css-tree: 1.1.3
|
css-tree: 1.1.3
|
||||||
|
|||||||
@@ -1,39 +1,62 @@
|
|||||||
import React, { useRef, useState } from 'react'
|
import { useState, useCallback } from 'react'
|
||||||
import { Button, ScrollView, Text, View } from 'react-native'
|
import { Pressable, Text, View, FlatList } from 'react-native'
|
||||||
|
import { AddIcon, GlobeIcon, Icon, PlayIcon, SettingsIcon } from '@/components/ui/icon'
|
||||||
|
import { Menu, MenuItem, MenuItemLabel } from '@/components/ui/menu'
|
||||||
|
|
||||||
export default function ScrollToExample() {
|
export default function Example() {
|
||||||
const scrollRef = useRef<ScrollView>(null)
|
const data = Array.from({ length: 1000 }, (_, i) => i + 1)
|
||||||
const [positions, setPositions] = useState<Record<string, number>>({})
|
const [openIndex, setOpenIndex] = useState<number | null>(null) // 控制哪个菜单打开
|
||||||
|
|
||||||
const handleLayout = (name: string, event: any) => {
|
const renderItem = useCallback(
|
||||||
const { y } = event.nativeEvent.layout
|
({ item: index }) => (
|
||||||
setPositions(prev => ({ ...prev, [name]: y }))
|
<View style={{ marginVertical: 10 }}>
|
||||||
}
|
<Menu
|
||||||
|
placement="top"
|
||||||
const scrollToField = (name: string) => {
|
offset={5}
|
||||||
const y = positions[name]
|
disabledKeys={['Settings']}
|
||||||
if (typeof y === 'number' && scrollRef.current) {
|
isOpen={openIndex === index}
|
||||||
scrollRef.current.scrollTo({ y, animated: true })
|
onOpen={() => setOpenIndex(index)}
|
||||||
}
|
onClose={() => setOpenIndex(null)}
|
||||||
}
|
trigger={({ onPress, ...triggerProps }) => (
|
||||||
|
<Pressable {...triggerProps} onLongPress={onPress}>
|
||||||
|
<Text>Menu {index}</Text>
|
||||||
|
</Pressable>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{openIndex === index && (
|
||||||
|
<>
|
||||||
|
<MenuItem key="Add account" textValue="Add account">
|
||||||
|
<Icon as={AddIcon} size="sm" className="mr-2" />
|
||||||
|
<MenuItemLabel size="sm">Add account - {index}</MenuItemLabel>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="Community" textValue="Community">
|
||||||
|
<Icon as={GlobeIcon} size="sm" className="mr-2" />
|
||||||
|
<MenuItemLabel size="sm">Community - {index}</MenuItemLabel>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="Plugins" textValue="Plugins">
|
||||||
|
<Icon as={PlayIcon} size="sm" className="mr-2" />
|
||||||
|
<MenuItemLabel size="sm">Plugins - {index}</MenuItemLabel>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem key="Settings" textValue="Settings">
|
||||||
|
<Icon as={SettingsIcon} size="sm" className="mr-2" />
|
||||||
|
<MenuItemLabel size="sm">Settings - {index}</MenuItemLabel>
|
||||||
|
</MenuItem>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Menu>
|
||||||
|
</View>
|
||||||
|
),
|
||||||
|
[openIndex]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1, paddingTop: 40 }}>
|
<FlatList
|
||||||
<Button title="滚动到 Password" onPress={() => scrollToField('password')} />
|
data={data}
|
||||||
|
renderItem={renderItem}
|
||||||
<ScrollView ref={scrollRef} style={{ marginTop: 20 }}>
|
keyExtractor={(item) => item.toString()}
|
||||||
<View onLayout={e => handleLayout('username', e)} style={{ height: 300, backgroundColor: '#f9c2ff', justifyContent: 'center', alignItems: 'center' }}>
|
initialNumToRender={20}
|
||||||
<Text>Username 区域</Text>
|
maxToRenderPerBatch={20}
|
||||||
</View>
|
windowSize={10}
|
||||||
|
/>
|
||||||
<View onLayout={e => handleLayout('email', e)} style={{ height: 300, backgroundColor: '#c2f9ff', justifyContent: 'center', alignItems: 'center' }}>
|
|
||||||
<Text>Email 区域</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View onLayout={e => handleLayout('password', e)} style={{ height: 300, backgroundColor: '#ffc2c2', justifyContent: 'center', alignItems: 'center' }}>
|
|
||||||
<Text>Password 区域</Text>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { MoneyCategoryItem, QueryMoneyCategoryResult } from '@/types/money/category'
|
import type { MoneyCategoryItem, QueryMoneyCategoryResult } from '@/types/money/category'
|
||||||
import type { MoneyRecordBase, MoneyRecordItem } from '@/types/money/record'
|
import type { MoneyRecordBase, MoneyRecordItem } from '@/types/money/record'
|
||||||
import Big from 'big.js'
|
import Big from 'big.js'
|
||||||
import { useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import { FlatList, Keyboard, Pressable, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native'
|
import { FlatList, Keyboard, Pressable, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native'
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||||
import { AInput, LucideIcon } from '@/components/common/ao'
|
import { AInput, LucideIcon } from '@/components/common/ao'
|
||||||
@@ -15,14 +15,15 @@ import {
|
|||||||
} from '@/components/ui/drawer'
|
} from '@/components/ui/drawer'
|
||||||
import { useKeyboardHeight } from '@/hooks/useKeyboardHeight'
|
import { useKeyboardHeight } from '@/hooks/useKeyboardHeight'
|
||||||
import { queryMoneyCategoryApi } from '@/request/api/money/category'
|
import { queryMoneyCategoryApi } from '@/request/api/money/category'
|
||||||
import { insertMoneyRecordApi } from '@/request/api/money/record'
|
import { insertMoneyRecordApi, updateMoneyRecordApi } from '@/request/api/money/record'
|
||||||
import { getCurrentDate } from '@/utils/time'
|
import { getCurrentDate, toDateString } from '@/utils/time'
|
||||||
import { toast } from '@/utils/toast'
|
import { toast } from '@/utils/toast'
|
||||||
import MoneyCategoryIcon from './MoneyCategoryIcon'
|
import MoneyCategoryIcon from './MoneyCategoryIcon'
|
||||||
|
|
||||||
interface AddMoneyDrawerProps {
|
interface AddMoneyDrawerProps {
|
||||||
isOpen: boolean
|
isOpen: boolean
|
||||||
onClose: () => void
|
updateData?: MoneyRecordItem | null
|
||||||
|
onClose?: () => void
|
||||||
onConfirm?: (result: MoneyRecordItem) => void
|
onConfirm?: (result: MoneyRecordItem) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ export default function AddMoneyDrawer({
|
|||||||
isOpen,
|
isOpen,
|
||||||
onClose,
|
onClose,
|
||||||
onConfirm,
|
onConfirm,
|
||||||
|
updateData,
|
||||||
}: AddMoneyDrawerProps) {
|
}: AddMoneyDrawerProps) {
|
||||||
const insets = useSafeAreaInsets()
|
const insets = useSafeAreaInsets()
|
||||||
// 选择顺序:0 支出 1收入
|
// 选择顺序:0 支出 1收入
|
||||||
@@ -114,6 +116,35 @@ export default function AddMoneyDrawer({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (updateData) {
|
||||||
|
const type = updateData.category_type
|
||||||
|
setSelectedIndex(type)
|
||||||
|
setMoneyRecord({
|
||||||
|
...updateData,
|
||||||
|
record_time: toDateString(updateData.record_time),
|
||||||
|
})
|
||||||
|
setShowKeydown(true)
|
||||||
|
|
||||||
|
if (type === 0) {
|
||||||
|
// 支出
|
||||||
|
categories.expense.forEach((item) => {
|
||||||
|
if (item.id === updateData.category_id) {
|
||||||
|
setSelectedCategory(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else if (type === 1) {
|
||||||
|
// 收入
|
||||||
|
categories.income.forEach((item) => {
|
||||||
|
if (item.id === updateData.category_id) {
|
||||||
|
setSelectedCategory(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [categories])
|
||||||
|
|
||||||
function resetData() {
|
function resetData() {
|
||||||
// 清空键盘记录
|
// 清空键盘记录
|
||||||
setKeydownInput('')
|
setKeydownInput('')
|
||||||
@@ -133,7 +164,7 @@ export default function AddMoneyDrawer({
|
|||||||
function onMainDrawerClose() {
|
function onMainDrawerClose() {
|
||||||
resetData()
|
resetData()
|
||||||
|
|
||||||
onClose()
|
onClose?.()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算过程
|
// 计算过程
|
||||||
@@ -314,7 +345,6 @@ export default function AddMoneyDrawer({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存
|
|
||||||
// 保存
|
// 保存
|
||||||
function saveRecord() {
|
function saveRecord() {
|
||||||
if (selectedCategory === null) {
|
if (selectedCategory === null) {
|
||||||
@@ -334,33 +364,62 @@ export default function AddMoneyDrawer({
|
|||||||
// 去掉金额负号
|
// 去掉金额负号
|
||||||
const amount = moneyRecord.amount.replace(/^-+/, '')
|
const amount = moneyRecord.amount.replace(/^-+/, '')
|
||||||
|
|
||||||
insertMoneyRecordApi({
|
const isUpdate = updateData && updateData !== null
|
||||||
...moneyRecord,
|
|
||||||
amount,
|
|
||||||
category_id: selectedCategory.id,
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
if (res.isSuccess) {
|
|
||||||
resetData()
|
|
||||||
|
|
||||||
|
if (isUpdate) {
|
||||||
|
updateMoneyRecordApi({
|
||||||
|
id: moneyRecord.id,
|
||||||
|
category_id: selectedCategory.id,
|
||||||
|
amount,
|
||||||
|
remark: moneyRecord.remark,
|
||||||
|
record_time: moneyRecord.record_time,
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.isSuccess) {
|
||||||
const result: MoneyRecordItem = {
|
const result: MoneyRecordItem = {
|
||||||
...res.data,
|
...moneyRecord,
|
||||||
|
category_id: selectedCategory.id,
|
||||||
category_name: selectedCategory.name,
|
category_name: selectedCategory.name,
|
||||||
category_icon: selectedCategory.icon,
|
category_icon: selectedCategory.icon,
|
||||||
category_type: selectedCategory.type,
|
category_type: selectedCategory.type,
|
||||||
}
|
}
|
||||||
|
|
||||||
onConfirm?.(result)
|
onConfirm?.(result)
|
||||||
|
|
||||||
|
resetData()
|
||||||
}
|
}
|
||||||
else {
|
}).catch((err) => {
|
||||||
toast.show({
|
|
||||||
title: res.message || '保存失败',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.log(err)
|
console.log(err)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
insertMoneyRecordApi({
|
||||||
|
...moneyRecord,
|
||||||
|
amount,
|
||||||
|
category_id: selectedCategory.id,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.isSuccess) {
|
||||||
|
|
||||||
|
const result: MoneyRecordItem = {
|
||||||
|
...res.data,
|
||||||
|
category_name: selectedCategory.name,
|
||||||
|
category_icon: selectedCategory.icon,
|
||||||
|
category_type: selectedCategory.type,
|
||||||
|
}
|
||||||
|
|
||||||
|
onConfirm?.(result)
|
||||||
|
resetData()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
toast.show({
|
||||||
|
title: res.message || '保存失败',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,14 +1,25 @@
|
|||||||
import type { MoneyRecordGroup } from '@/types/money/record'
|
import type { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record'
|
||||||
import React from 'react'
|
import React, { useCallback, useState } from 'react'
|
||||||
import { SectionList, Text, View } from 'react-native'
|
import { Pressable, SectionList, Text, View } from 'react-native'
|
||||||
|
import { LucideIcon } from '@/components/common/ao'
|
||||||
import EmptyState from '@/components/common/EmptyStatus'
|
import EmptyState from '@/components/common/EmptyStatus'
|
||||||
|
import { Badge, BadgeText } from '@/components/ui/badge'
|
||||||
|
import { Menu, MenuItem, MenuItemLabel } from '@/components/ui/menu'
|
||||||
import MoneyCategoryIcon from './MoneyCategoryIcon'
|
import MoneyCategoryIcon from './MoneyCategoryIcon'
|
||||||
|
|
||||||
interface StaticTransactionsProps {
|
interface StaticTransactionsProps {
|
||||||
records: MoneyRecordGroup[]
|
records: MoneyRecordGroup[]
|
||||||
|
onUpdate?: (data: MoneyRecordItem) => void
|
||||||
|
onDelete?: (id: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function StaticTransactions({ records }: StaticTransactionsProps) {
|
export default function StaticTransactions({
|
||||||
|
records,
|
||||||
|
onUpdate,
|
||||||
|
onDelete,
|
||||||
|
}: StaticTransactionsProps) {
|
||||||
|
const [selectedId, setSelectedId] = useState<number | null>(null)
|
||||||
|
|
||||||
if (records.length === 0) {
|
if (records.length === 0) {
|
||||||
return (
|
return (
|
||||||
<EmptyState
|
<EmptyState
|
||||||
@@ -33,7 +44,7 @@ export default function StaticTransactions({ records }: StaticTransactionsProps)
|
|||||||
stickySectionHeadersEnabled={true}
|
stickySectionHeadersEnabled={true}
|
||||||
showsVerticalScrollIndicator={false}
|
showsVerticalScrollIndicator={false}
|
||||||
renderSectionHeader={({ section }) => (
|
renderSectionHeader={({ section }) => (
|
||||||
<View className="bg-white py-2 px-1 border-b border-gray-100 mb-2">
|
<View className="bg-white py-2 px-4 border-b border-gray-100 mb-2">
|
||||||
<View className="flex-row items-center justify-between">
|
<View className="flex-row items-center justify-between">
|
||||||
<Text className="text-gray-700 font-semibold text-base">
|
<Text className="text-gray-700 font-semibold text-base">
|
||||||
{section.title}
|
{section.title}
|
||||||
@@ -63,31 +74,82 @@ export default function StaticTransactions({ records }: StaticTransactionsProps)
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => {
|
||||||
<View className="flex-row items-center mb-4 gap-4">
|
const isOpen = item.id === selectedId
|
||||||
<View className="w-10 h-10 rounded-full bg-gray-100 items-center justify-center">
|
|
||||||
<MoneyCategoryIcon name={item.category_icon} size={22} color="#000" />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View className="flex-1">
|
return (
|
||||||
<Text className="text-gray-800 font-medium text-base">
|
<Menu
|
||||||
{item.category_name}
|
placement="bottom"
|
||||||
</Text>
|
offset={5}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClose={() => setSelectedId(null)}
|
||||||
|
trigger={({ onLongPress, onPressOut, delayLongPress, android_ripple, ...triggerProps }) => (
|
||||||
|
<Pressable
|
||||||
|
{...triggerProps}
|
||||||
|
onLongPress={() => setSelectedId(item.id)}
|
||||||
|
delayLongPress={200}
|
||||||
|
android_ripple={undefined}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
className="flex-row items-center gap-4 py-2 px-5"
|
||||||
|
style={{
|
||||||
|
backgroundColor: item.id === selectedId ? '#f2f2f2' : 'transparent',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View className="w-10 h-10 rounded-full bg-gray-100 items-center justify-center">
|
||||||
|
<MoneyCategoryIcon name={item.category_icon} size={22} color="#000" />
|
||||||
|
</View>
|
||||||
|
|
||||||
{item.remark && (
|
<View className="flex-1">
|
||||||
<Text className="text-gray-400 text-sm">{item.remark}</Text>
|
<Text className="text-gray-800 font-medium text-base">{item.category_name}</Text>
|
||||||
|
{item.remark && <Text className="text-gray-400 text-sm">{item.remark}</Text>}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className="flex-row flex">
|
||||||
|
<Text className="text-sm text-gray-500">
|
||||||
|
{item.category_type === 1 ? '+' : '-'}
|
||||||
|
{' '}
|
||||||
|
{item.amount}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Badge size='sm' variant='solid' action='muted'>
|
||||||
|
<BadgeText>宝贝</BadgeText>
|
||||||
|
</Badge>
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
)}
|
)}
|
||||||
</View>
|
>
|
||||||
|
{isOpen && (
|
||||||
<View className="flex-row flex">
|
<>
|
||||||
<Text className="text-sm text-gray-500">
|
<MenuItem
|
||||||
{item.category_type === 0 ? '+' : '-'}
|
key="update"
|
||||||
{' '}
|
textValue="update"
|
||||||
{item.amount}
|
onPress={() => {
|
||||||
</Text>
|
onUpdate?.(item)
|
||||||
</View>
|
}}
|
||||||
</View>
|
>
|
||||||
)}
|
<LucideIcon icon="Pencil" size={14} className="mr-2" />
|
||||||
|
<MenuItemLabel size="sm">
|
||||||
|
修改
|
||||||
|
</MenuItemLabel>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
key="delete"
|
||||||
|
textValue="delete"
|
||||||
|
onPress={() => {
|
||||||
|
onDelete?.(item.id)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LucideIcon icon="Trash2" size={14} className="mr-2" />
|
||||||
|
<MenuItemLabel size="sm">
|
||||||
|
删除
|
||||||
|
</MenuItemLabel>
|
||||||
|
</MenuItem>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Menu>
|
||||||
|
)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import type { MoneyRecordGroup, MoneyRecordItem, QueryMoneyRecordsResult } from '@/types/money/record'
|
import type { MoneyRecordGroup, MoneyRecordItem, QueryMoneyRecordsResult } from '@/types/money/record'
|
||||||
import Big from 'big.js'
|
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { Text, TouchableOpacity, View } from 'react-native'
|
import { Text, TouchableOpacity, View } from 'react-native'
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||||
@@ -7,9 +6,9 @@ import { ADatePicker, LucideIcon } from '@/components/common/ao'
|
|||||||
import { Fab, FabIcon } from '@/components/ui/fab'
|
import { Fab, FabIcon } from '@/components/ui/fab'
|
||||||
import { AddIcon } from '@/components/ui/icon'
|
import { AddIcon } from '@/components/ui/icon'
|
||||||
import { Progress, ProgressFilledTrack } from '@/components/ui/progress'
|
import { Progress, ProgressFilledTrack } from '@/components/ui/progress'
|
||||||
import { queryMoneyRecordsApi } from '@/request/api/money/record'
|
import { deleteMoneyRecordApi, queryMoneyRecordsApi } from '@/request/api/money/record'
|
||||||
import { add, sub } from '@/utils/math'
|
import { add, sub } from '@/utils/math'
|
||||||
import { getCurrentYearMonth } from '@/utils/time'
|
import { getCurrentYearMonth, isInMonth } from '@/utils/time'
|
||||||
import { toast } from '@/utils/toast'
|
import { toast } from '@/utils/toast'
|
||||||
import AddMoneyDrawer from './components/AddDrawer'
|
import AddMoneyDrawer from './components/AddDrawer'
|
||||||
import TransactionsList from './components/TransactionsList'
|
import TransactionsList from './components/TransactionsList'
|
||||||
@@ -30,6 +29,8 @@ export default function Money() {
|
|||||||
total_income: '0',
|
total_income: '0',
|
||||||
records: [],
|
records: [],
|
||||||
})
|
})
|
||||||
|
// 更新
|
||||||
|
const [updateItem, setUpdateItem] = useState<MoneyRecordItem | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
queryMoneyRecordsApi({
|
queryMoneyRecordsApi({
|
||||||
@@ -53,6 +54,11 @@ export default function Money() {
|
|||||||
const recordTime = data.record_time
|
const recordTime = data.record_time
|
||||||
|
|
||||||
setMoneyRecords((prev) => {
|
setMoneyRecords((prev) => {
|
||||||
|
// 不在当前月份 → 不添加,直接返回
|
||||||
|
if (!isInMonth(recordTime, searchParams.record_time)) {
|
||||||
|
return prev
|
||||||
|
}
|
||||||
|
|
||||||
const next = structuredClone(prev)
|
const next = structuredClone(prev)
|
||||||
|
|
||||||
// 查找分组
|
// 查找分组
|
||||||
@@ -64,12 +70,12 @@ export default function Money() {
|
|||||||
group.records.unshift(data)
|
group.records.unshift(data)
|
||||||
|
|
||||||
// 更新分组 & 总计
|
// 更新分组 & 总计
|
||||||
if (data.category_type === 0) {
|
if (data.category_type === 1) {
|
||||||
// 收入
|
// 收入
|
||||||
group.income = add(group.income, data.amount)
|
group.income = add(group.income, data.amount)
|
||||||
next.total_income = add(next.total_income, data.amount)
|
next.total_income = add(next.total_income, data.amount)
|
||||||
}
|
}
|
||||||
else if (data.category_type === 1) {
|
else if (data.category_type === 0) {
|
||||||
// 支出
|
// 支出
|
||||||
group.expense = add(group.expense, data.amount)
|
group.expense = add(group.expense, data.amount)
|
||||||
next.total_expense = add(next.total_expense, data.amount)
|
next.total_expense = add(next.total_expense, data.amount)
|
||||||
@@ -79,8 +85,8 @@ export default function Money() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// === 无分组,新建 ===
|
// === 无分组,新建 ===
|
||||||
const income = data.category_type === 0 ? data.amount : '0'
|
const expense = data.category_type === 0 ? data.amount : '0'
|
||||||
const expense = data.category_type === 1 ? data.amount : '0'
|
const income = data.category_type === 1 ? data.amount : '0'
|
||||||
|
|
||||||
const newGroup: MoneyRecordGroup = {
|
const newGroup: MoneyRecordGroup = {
|
||||||
record_time: recordTime,
|
record_time: recordTime,
|
||||||
@@ -94,11 +100,9 @@ export default function Money() {
|
|||||||
const index = next.records.findIndex(g => g.record_time < recordTime)
|
const index = next.records.findIndex(g => g.record_time < recordTime)
|
||||||
|
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
// 所有日期都比它大 → 插入最后
|
|
||||||
next.records.push(newGroup)
|
next.records.push(newGroup)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// 插入正确位置
|
|
||||||
next.records.splice(index, 0, newGroup)
|
next.records.splice(index, 0, newGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +118,164 @@ export default function Money() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleUpdateMoneyRecord(updated: MoneyRecordItem) {
|
||||||
|
setMoneyRecords((prev) => {
|
||||||
|
const next = structuredClone(prev)
|
||||||
|
|
||||||
|
// 找到旧记录
|
||||||
|
const oldGroupIndex = next.records.findIndex(g =>
|
||||||
|
g.records.some(r => r.id === updated.id),
|
||||||
|
)
|
||||||
|
if (oldGroupIndex === -1)
|
||||||
|
return next
|
||||||
|
|
||||||
|
const oldGroup = next.records[oldGroupIndex]
|
||||||
|
const oldRecordIndex = oldGroup.records.findIndex(r => r.id === updated.id)
|
||||||
|
const oldRecord = oldGroup.records[oldRecordIndex]
|
||||||
|
|
||||||
|
const oldAmount = oldRecord.amount
|
||||||
|
const newAmount = updated.amount
|
||||||
|
const oldType = oldRecord.category_type
|
||||||
|
const newType = updated.category_type
|
||||||
|
const oldDate = oldRecord.record_time
|
||||||
|
const newDate = updated.record_time
|
||||||
|
|
||||||
|
// record_time 没变 → 同分组更新
|
||||||
|
if (oldDate === newDate) {
|
||||||
|
oldGroup.records[oldRecordIndex] = updated
|
||||||
|
|
||||||
|
// 调整分组金额
|
||||||
|
if (oldType === 1)
|
||||||
|
oldGroup.income = sub(oldGroup.income, oldAmount)
|
||||||
|
if (oldType === 0)
|
||||||
|
oldGroup.expense = sub(oldGroup.expense, oldAmount)
|
||||||
|
|
||||||
|
if (newType === 1)
|
||||||
|
oldGroup.income = add(oldGroup.income, newAmount)
|
||||||
|
if (newType === 0)
|
||||||
|
oldGroup.expense = add(oldGroup.expense, newAmount)
|
||||||
|
|
||||||
|
// 调整总计
|
||||||
|
if (oldType === 1)
|
||||||
|
next.total_income = sub(next.total_income, oldAmount)
|
||||||
|
if (oldType === 0)
|
||||||
|
next.total_expense = sub(next.total_expense, oldAmount)
|
||||||
|
|
||||||
|
if (newType === 1)
|
||||||
|
next.total_income = add(next.total_income, newAmount)
|
||||||
|
if (newType === 0)
|
||||||
|
next.total_expense = add(next.total_expense, newAmount)
|
||||||
|
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// 判断是否在当前月份内
|
||||||
|
// -------------------------
|
||||||
|
const currentMonth = searchParams.record_time // 例如 "2025-01"
|
||||||
|
|
||||||
|
const isInCurrentMonth = isInMonth(newDate, currentMonth)
|
||||||
|
|
||||||
|
// 1. 先移除旧分组 & 调整金额(无论是否在当前月份,都要做)
|
||||||
|
if (oldType === 1)
|
||||||
|
oldGroup.income = sub(oldGroup.income, oldAmount)
|
||||||
|
if (oldType === 0)
|
||||||
|
oldGroup.expense = sub(oldGroup.expense, oldAmount)
|
||||||
|
|
||||||
|
if (oldType === 1)
|
||||||
|
next.total_income = sub(next.total_income, oldAmount)
|
||||||
|
if (oldType === 0)
|
||||||
|
next.total_expense = sub(next.total_expense, oldAmount)
|
||||||
|
|
||||||
|
oldGroup.records.splice(oldRecordIndex, 1)
|
||||||
|
if (oldGroup.records.length === 0) {
|
||||||
|
next.records.splice(oldGroupIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// 不在当前月份 → 不显示,直接返回 next
|
||||||
|
// -------------------------
|
||||||
|
if (!isInCurrentMonth) {
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------
|
||||||
|
// 在当前月份 → 移动到新分组
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
// 找新分组,如果没有就创建
|
||||||
|
let newGroup = next.records.find(g => g.record_time === newDate)
|
||||||
|
if (!newGroup) {
|
||||||
|
newGroup = {
|
||||||
|
record_time: newDate,
|
||||||
|
income: '0.00',
|
||||||
|
expense: '0.00',
|
||||||
|
records: [],
|
||||||
|
}
|
||||||
|
// 按日期倒序插入
|
||||||
|
const insertIndex = next.records.findIndex(g => g.record_time < newDate)
|
||||||
|
if (insertIndex === -1)
|
||||||
|
next.records.push(newGroup)
|
||||||
|
else
|
||||||
|
next.records.splice(insertIndex, 0, newGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加到新分组
|
||||||
|
newGroup.records.unshift(updated)
|
||||||
|
|
||||||
|
// 加金额
|
||||||
|
if (newType === 1)
|
||||||
|
newGroup.income = add(newGroup.income, newAmount)
|
||||||
|
if (newType === 0)
|
||||||
|
newGroup.expense = add(newGroup.expense, newAmount)
|
||||||
|
|
||||||
|
if (newType === 1)
|
||||||
|
next.total_income = add(next.total_income, newAmount)
|
||||||
|
if (newType === 0)
|
||||||
|
next.total_expense = add(next.total_expense, newAmount)
|
||||||
|
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDeleteRecord(id: number) {
|
||||||
|
// 直接更新本地状态
|
||||||
|
setMoneyRecords((prev) => {
|
||||||
|
const next = structuredClone(prev)
|
||||||
|
|
||||||
|
// 遍历每个分组
|
||||||
|
next.records.forEach((group) => {
|
||||||
|
const index = group.records.findIndex(r => r.id === id)
|
||||||
|
if (index !== -1) {
|
||||||
|
const record = group.records[index]
|
||||||
|
|
||||||
|
// 更新分组金额
|
||||||
|
if (record.category_type === 1) {
|
||||||
|
group.income = sub(group.income, record.amount)
|
||||||
|
next.total_income = sub(next.total_income, record.amount)
|
||||||
|
}
|
||||||
|
else if (record.category_type === 0) {
|
||||||
|
group.expense = sub(group.expense, record.amount)
|
||||||
|
next.total_expense = sub(next.total_expense, record.amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除记录
|
||||||
|
group.records.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 删除空分组
|
||||||
|
next.records = next.records.filter(g => g.records.length > 0)
|
||||||
|
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
|
||||||
|
// 异步请求删除 API
|
||||||
|
deleteMoneyRecordApi({ id }).catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
@@ -122,7 +284,7 @@ export default function Money() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<View>
|
<View>
|
||||||
<View className="flex flex-row justify-between items-center px-4">
|
<View className="flex flex-row justify-between items-center px-3">
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => setShowDatePicker(true)}
|
onPress={() => setShowDatePicker(true)}
|
||||||
className="flex flex-row items-center gap-1"
|
className="flex flex-row items-center gap-1"
|
||||||
@@ -198,8 +360,17 @@ export default function Money() {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View className="flex-1 px-4 mt-2">
|
<View className="flex-1 mt-2">
|
||||||
<TransactionsList records={moneyRecords.records} />
|
<TransactionsList
|
||||||
|
records={moneyRecords.records}
|
||||||
|
onUpdate={(data) => {
|
||||||
|
setUpdateItem(data)
|
||||||
|
setShowAddDrawer(true)
|
||||||
|
}}
|
||||||
|
onDelete={(id) => {
|
||||||
|
handleDeleteRecord(id)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Fab
|
<Fab
|
||||||
@@ -213,12 +384,20 @@ export default function Money() {
|
|||||||
|
|
||||||
<AddMoneyDrawer
|
<AddMoneyDrawer
|
||||||
isOpen={showAddDrawer}
|
isOpen={showAddDrawer}
|
||||||
|
updateData={updateItem}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setShowAddDrawer(false)
|
setShowAddDrawer(false)
|
||||||
|
setUpdateItem(null)
|
||||||
}}
|
}}
|
||||||
onConfirm={(res) => {
|
onConfirm={(res) => {
|
||||||
setShowAddDrawer(false)
|
setShowAddDrawer(false)
|
||||||
handleAddMoneyRecord(res)
|
if (updateItem !== null) {
|
||||||
|
setUpdateItem(null)
|
||||||
|
handleUpdateMoneyRecord(res)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
handleAddMoneyRecord(res)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export default function User() {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<AButton onPress={() => {
|
<AButton onPress={() => {
|
||||||
router.replace('/auth/login')
|
router.replace('/auth')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
跳转到登陆页面
|
跳转到登陆页面
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
'use client';
|
||||||
|
import React from 'react';
|
||||||
|
import { Text, View } from 'react-native';
|
||||||
|
import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator';
|
||||||
|
import { tva } from '@gluestack-ui/utils/nativewind-utils';
|
||||||
|
import {
|
||||||
|
withStyleContext,
|
||||||
|
useStyleContext,
|
||||||
|
} from '@gluestack-ui/utils/nativewind-utils';
|
||||||
|
import { cssInterop } from 'nativewind';
|
||||||
|
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
|
||||||
|
|
||||||
|
import { Svg } from 'react-native-svg';
|
||||||
|
const SCOPE = 'BADGE';
|
||||||
|
|
||||||
|
const badgeStyle = tva({
|
||||||
|
base: 'flex-row items-center rounded-sm data-[disabled=true]:opacity-50 px-2 py-1',
|
||||||
|
variants: {
|
||||||
|
action: {
|
||||||
|
error: 'bg-background-error border-error-300',
|
||||||
|
warning: 'bg-background-warning border-warning-300',
|
||||||
|
success: 'bg-background-success border-success-300',
|
||||||
|
info: 'bg-background-info border-info-300',
|
||||||
|
muted: 'bg-background-muted border-background-300',
|
||||||
|
},
|
||||||
|
variant: {
|
||||||
|
solid: '',
|
||||||
|
outline: 'border',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
sm: '',
|
||||||
|
md: '',
|
||||||
|
lg: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const badgeTextStyle = tva({
|
||||||
|
base: 'text-typography-700 font-body font-normal tracking-normal uppercase',
|
||||||
|
|
||||||
|
parentVariants: {
|
||||||
|
action: {
|
||||||
|
error: 'text-error-600',
|
||||||
|
warning: 'text-warning-600',
|
||||||
|
success: 'text-success-600',
|
||||||
|
info: 'text-info-600',
|
||||||
|
muted: 'text-background-800',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
sm: 'text-2xs',
|
||||||
|
md: 'text-xs',
|
||||||
|
lg: 'text-sm',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variants: {
|
||||||
|
isTruncated: {
|
||||||
|
true: 'web:truncate',
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
true: 'font-bold',
|
||||||
|
},
|
||||||
|
underline: {
|
||||||
|
true: 'underline',
|
||||||
|
},
|
||||||
|
strikeThrough: {
|
||||||
|
true: 'line-through',
|
||||||
|
},
|
||||||
|
sub: {
|
||||||
|
true: 'text-xs',
|
||||||
|
},
|
||||||
|
italic: {
|
||||||
|
true: 'italic',
|
||||||
|
},
|
||||||
|
highlight: {
|
||||||
|
true: 'bg-yellow-500',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const badgeIconStyle = tva({
|
||||||
|
base: 'fill-none',
|
||||||
|
parentVariants: {
|
||||||
|
action: {
|
||||||
|
error: 'text-error-600',
|
||||||
|
warning: 'text-warning-600',
|
||||||
|
success: 'text-success-600',
|
||||||
|
info: 'text-info-600',
|
||||||
|
muted: 'text-background-800',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
sm: 'h-3 w-3',
|
||||||
|
md: 'h-3.5 w-3.5',
|
||||||
|
lg: 'h-4 w-4',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const ContextView = withStyleContext(View, SCOPE);
|
||||||
|
|
||||||
|
cssInterop(PrimitiveIcon, {
|
||||||
|
className: {
|
||||||
|
target: 'style',
|
||||||
|
nativeStyleToProp: {
|
||||||
|
height: true,
|
||||||
|
width: true,
|
||||||
|
fill: true,
|
||||||
|
color: 'classNameColor',
|
||||||
|
stroke: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
type IBadgeProps = React.ComponentPropsWithoutRef<typeof ContextView> &
|
||||||
|
VariantProps<typeof badgeStyle>;
|
||||||
|
function Badge({
|
||||||
|
children,
|
||||||
|
action = 'muted',
|
||||||
|
variant = 'solid',
|
||||||
|
size = 'md',
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: { className?: string } & IBadgeProps) {
|
||||||
|
return (
|
||||||
|
<ContextView
|
||||||
|
className={badgeStyle({ action, variant, class: className })}
|
||||||
|
{...props}
|
||||||
|
context={{
|
||||||
|
action,
|
||||||
|
variant,
|
||||||
|
size,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ContextView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
type IBadgeTextProps = React.ComponentPropsWithoutRef<typeof Text> &
|
||||||
|
VariantProps<typeof badgeTextStyle>;
|
||||||
|
|
||||||
|
const BadgeText = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof Text>,
|
||||||
|
IBadgeTextProps
|
||||||
|
>(function BadgeText({ children, className, size, ...props }, ref) {
|
||||||
|
const { size: parentSize, action: parentAction } = useStyleContext(SCOPE);
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
ref={ref}
|
||||||
|
className={badgeTextStyle({
|
||||||
|
parentVariants: {
|
||||||
|
size: parentSize,
|
||||||
|
action: parentAction,
|
||||||
|
},
|
||||||
|
size,
|
||||||
|
class: className,
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
type IBadgeIconProps = React.ComponentPropsWithoutRef<typeof PrimitiveIcon> &
|
||||||
|
VariantProps<typeof badgeIconStyle>;
|
||||||
|
|
||||||
|
const BadgeIcon = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof Svg>,
|
||||||
|
IBadgeIconProps
|
||||||
|
>(function BadgeIcon({ className, size, ...props }, ref) {
|
||||||
|
const { size: parentSize, action: parentAction } = useStyleContext(SCOPE);
|
||||||
|
|
||||||
|
if (typeof size === 'number') {
|
||||||
|
return (
|
||||||
|
<UIIcon
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
className={badgeIconStyle({ class: className })}
|
||||||
|
size={size}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else if (
|
||||||
|
(props?.height !== undefined || props?.width !== undefined) &&
|
||||||
|
size === undefined
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<UIIcon
|
||||||
|
ref={ref}
|
||||||
|
{...props}
|
||||||
|
className={badgeIconStyle({ class: className })}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<UIIcon
|
||||||
|
className={badgeIconStyle({
|
||||||
|
parentVariants: {
|
||||||
|
size: parentSize,
|
||||||
|
action: parentAction,
|
||||||
|
},
|
||||||
|
size,
|
||||||
|
class: className,
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Badge.displayName = 'Badge';
|
||||||
|
BadgeText.displayName = 'BadgeText';
|
||||||
|
BadgeIcon.displayName = 'BadgeIcon';
|
||||||
|
|
||||||
|
export { Badge, BadgeIcon, BadgeText };
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
'use client'
|
||||||
|
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'
|
||||||
|
import type {
|
||||||
|
MotionComponentProps,
|
||||||
|
} from '@legendapp/motion'
|
||||||
|
import type { ViewStyle } from 'react-native'
|
||||||
|
import { createMenu } from '@gluestack-ui/core/menu/creator'
|
||||||
|
import { tva } from '@gluestack-ui/utils/nativewind-utils'
|
||||||
|
import {
|
||||||
|
AnimatePresence,
|
||||||
|
Motion,
|
||||||
|
} from '@legendapp/motion'
|
||||||
|
import { cssInterop } from 'nativewind'
|
||||||
|
import React from 'react'
|
||||||
|
import { Pressable, Text, View } from 'react-native'
|
||||||
|
|
||||||
|
type IMotionViewProps = React.ComponentProps<typeof View>
|
||||||
|
& MotionComponentProps<typeof View, ViewStyle, unknown, unknown, unknown>
|
||||||
|
|
||||||
|
const MotionView = Motion.View as React.ComponentType<IMotionViewProps>
|
||||||
|
|
||||||
|
const menuStyle = tva({
|
||||||
|
base: 'rounded-md bg-background-0 border border-outline-100 p-1 shadow-hard-5',
|
||||||
|
})
|
||||||
|
|
||||||
|
const menuItemStyle = tva({
|
||||||
|
base: 'min-w-[200px] p-3 flex-row items-center rounded data-[hover=true]:bg-background-50 data-[active=true]:bg-background-100 data-[focus=true]:bg-background-50 data-[focus=true]:web:outline-none data-[focus=true]:web:outline-0 data-[disabled=true]:opacity-40 data-[disabled=true]:web:cursor-not-allowed data-[focus-visible=true]:web:outline-2 data-[focus-visible=true]:web:outline-primary-700 data-[focus-visible=true]:web:outline data-[focus-visible=true]:web:cursor-pointer data-[disabled=true]:data-[focus=true]:bg-transparent',
|
||||||
|
})
|
||||||
|
|
||||||
|
const menuBackdropStyle = tva({
|
||||||
|
base: 'absolute top-0 bottom-0 left-0 right-0 web:cursor-default',
|
||||||
|
// add this classnames if you want to give background color to backdrop
|
||||||
|
// opacity-50 bg-background-500,
|
||||||
|
})
|
||||||
|
|
||||||
|
const menuSeparatorStyle = tva({
|
||||||
|
base: 'bg-background-200 h-px w-full',
|
||||||
|
})
|
||||||
|
|
||||||
|
const menuItemLabelStyle = tva({
|
||||||
|
base: 'text-typography-700 font-normal font-body',
|
||||||
|
|
||||||
|
variants: {
|
||||||
|
isTruncated: {
|
||||||
|
true: 'web:truncate',
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
true: 'font-bold',
|
||||||
|
},
|
||||||
|
underline: {
|
||||||
|
true: 'underline',
|
||||||
|
},
|
||||||
|
strikeThrough: {
|
||||||
|
true: 'line-through',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
'2xs': 'text-2xs',
|
||||||
|
'xs': 'text-xs',
|
||||||
|
'sm': 'text-sm',
|
||||||
|
'md': 'text-base',
|
||||||
|
'lg': 'text-lg',
|
||||||
|
'xl': 'text-xl',
|
||||||
|
'2xl': 'text-2xl',
|
||||||
|
'3xl': 'text-3xl',
|
||||||
|
'4xl': 'text-4xl',
|
||||||
|
'5xl': 'text-5xl',
|
||||||
|
'6xl': 'text-6xl',
|
||||||
|
},
|
||||||
|
sub: {
|
||||||
|
true: 'text-xs',
|
||||||
|
},
|
||||||
|
italic: {
|
||||||
|
true: 'italic',
|
||||||
|
},
|
||||||
|
highlight: {
|
||||||
|
true: 'bg-yellow-500',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const BackdropPressable = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof Pressable>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof Pressable>
|
||||||
|
& VariantProps<typeof menuBackdropStyle>
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
ref={ref}
|
||||||
|
className={menuBackdropStyle({
|
||||||
|
class: className,
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
type IMenuItemProps = VariantProps<typeof menuItemStyle> & {
|
||||||
|
className?: string
|
||||||
|
} & React.ComponentPropsWithoutRef<typeof Pressable>
|
||||||
|
|
||||||
|
const Item = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof Pressable>,
|
||||||
|
IMenuItemProps
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
ref={ref}
|
||||||
|
className={menuItemStyle({
|
||||||
|
class: className,
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const Separator = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof View>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof View>
|
||||||
|
& VariantProps<typeof menuSeparatorStyle>
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
ref={ref}
|
||||||
|
className={menuSeparatorStyle({ class: className })}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
export const UIMenu = createMenu({
|
||||||
|
Root: MotionView,
|
||||||
|
Item,
|
||||||
|
Label: Text,
|
||||||
|
Backdrop: BackdropPressable,
|
||||||
|
AnimatePresence,
|
||||||
|
Separator,
|
||||||
|
})
|
||||||
|
|
||||||
|
cssInterop(MotionView, { className: 'style' })
|
||||||
|
|
||||||
|
type IMenuProps = React.ComponentProps<typeof UIMenu>
|
||||||
|
& VariantProps<typeof menuStyle> & { className?: string }
|
||||||
|
type IMenuItemLabelProps = React.ComponentProps<typeof UIMenu.ItemLabel>
|
||||||
|
& VariantProps<typeof menuItemLabelStyle> & { className?: string }
|
||||||
|
|
||||||
|
const Menu = React.forwardRef<React.ComponentRef<typeof UIMenu>, IMenuProps>(
|
||||||
|
({ className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<UIMenu
|
||||||
|
ref={ref}
|
||||||
|
initial={{
|
||||||
|
opacity: 0,
|
||||||
|
scale: 0.8,
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
opacity: 1,
|
||||||
|
scale: 1,
|
||||||
|
}}
|
||||||
|
exit={{
|
||||||
|
opacity: 0,
|
||||||
|
scale: 0.8,
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
type: 'timing',
|
||||||
|
duration: 100,
|
||||||
|
}}
|
||||||
|
className={menuStyle({
|
||||||
|
class: className,
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const MenuItem = UIMenu.Item
|
||||||
|
|
||||||
|
const MenuItemLabel = React.forwardRef<
|
||||||
|
React.ComponentRef<typeof UIMenu.ItemLabel>,
|
||||||
|
IMenuItemLabelProps
|
||||||
|
>((
|
||||||
|
{
|
||||||
|
className,
|
||||||
|
isTruncated,
|
||||||
|
bold,
|
||||||
|
underline,
|
||||||
|
strikeThrough,
|
||||||
|
size = 'md',
|
||||||
|
sub,
|
||||||
|
italic,
|
||||||
|
highlight,
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
return (
|
||||||
|
<UIMenu.ItemLabel
|
||||||
|
ref={ref}
|
||||||
|
className={menuItemLabelStyle({
|
||||||
|
isTruncated: isTruncated as boolean,
|
||||||
|
bold: bold as boolean,
|
||||||
|
underline: underline as boolean,
|
||||||
|
strikeThrough: strikeThrough as boolean,
|
||||||
|
size,
|
||||||
|
sub: sub as boolean,
|
||||||
|
italic: italic as boolean,
|
||||||
|
highlight: highlight as boolean,
|
||||||
|
class: className,
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const MenuSeparator = UIMenu.Separator
|
||||||
|
|
||||||
|
Menu.displayName = 'Menu'
|
||||||
|
MenuItem.displayName = 'MenuItem'
|
||||||
|
MenuItemLabel.displayName = 'MenuItemLabel'
|
||||||
|
MenuSeparator.displayName = 'MenuSeparator'
|
||||||
|
export { Menu, MenuItem, MenuItemLabel, MenuSeparator }
|
||||||
@@ -1,4 +1,12 @@
|
|||||||
import type { InsertMoneyRecordParams, InsertMoneyRecordResult, QueryMoneyRecordsParams, QueryMoneyRecordsResult } from '@/types/money/record'
|
import type {
|
||||||
|
DeleteMoneyRecordParams,
|
||||||
|
InsertMoneyRecordParams,
|
||||||
|
InsertMoneyRecordResult,
|
||||||
|
QueryMoneyRecordsParams,
|
||||||
|
QueryMoneyRecordsResult,
|
||||||
|
UpdateMoneyRecordParams,
|
||||||
|
} from '@/types/money/record'
|
||||||
|
|
||||||
import alovaInstance from '../../index'
|
import alovaInstance from '../../index'
|
||||||
|
|
||||||
const API_PREFIX = '/money'
|
const API_PREFIX = '/money'
|
||||||
@@ -10,3 +18,11 @@ export function queryMoneyRecordsApi(params: QueryMoneyRecordsParams) {
|
|||||||
export function insertMoneyRecordApi(params: InsertMoneyRecordParams) {
|
export function insertMoneyRecordApi(params: InsertMoneyRecordParams) {
|
||||||
return alovaInstance.Post<ResponseData<InsertMoneyRecordResult>>(`${API_PREFIX}/insert`, params)
|
return alovaInstance.Post<ResponseData<InsertMoneyRecordResult>>(`${API_PREFIX}/insert`, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateMoneyRecordApi(params: UpdateMoneyRecordParams) {
|
||||||
|
return alovaInstance.Post<ResponseData<any>>(`${API_PREFIX}/update`, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteMoneyRecordApi(params: DeleteMoneyRecordParams) {
|
||||||
|
return alovaInstance.Post<ResponseData<any>>(`${API_PREFIX}/delete`, params)
|
||||||
|
}
|
||||||
@@ -30,8 +30,8 @@ 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,
|
||||||
cacheFor: null,
|
cacheFor: null,
|
||||||
|
|||||||
@@ -40,5 +40,12 @@ export interface QueryMoneyRecordsResult {
|
|||||||
// 新增请求参数
|
// 新增请求参数
|
||||||
export type InsertMoneyRecordParams = Omit<MoneyRecordBase, 'id' | 'create_time'>
|
export type InsertMoneyRecordParams = Omit<MoneyRecordBase, 'id' | 'create_time'>
|
||||||
|
|
||||||
// 新增返回结果
|
|
||||||
export interface InsertMoneyRecordResult extends MoneyRecordBase {}
|
export interface InsertMoneyRecordResult extends MoneyRecordBase {}
|
||||||
|
|
||||||
|
// 更新
|
||||||
|
export interface UpdateMoneyRecordParams extends Omit<MoneyRecordBase, 'create_time' | 'user_id'> {}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
export interface DeleteMoneyRecordParams {
|
||||||
|
id: number
|
||||||
|
}
|
||||||
@@ -2,31 +2,25 @@
|
|||||||
import Big from 'big.js'
|
import Big from 'big.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加法
|
* 加法(保留两位小数)
|
||||||
* @param a string number
|
|
||||||
* @param b string number
|
|
||||||
* @returns string number
|
|
||||||
*/
|
*/
|
||||||
export function add(a: string | number, b: string | number): string {
|
export function add(a: string | number, b: string | number): string {
|
||||||
try {
|
try {
|
||||||
return new Big(a).plus(new Big(b)).toString()
|
return new Big(a).plus(new Big(b)).toFixed(2) // ⭐ 保留两位
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
return '0'
|
return '0.00'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 减法
|
* 减法(保留两位小数)
|
||||||
* @param a string number
|
|
||||||
* @param b string number
|
|
||||||
* @returns string number
|
|
||||||
*/
|
*/
|
||||||
export function sub(a: string | number, b: string | number): string {
|
export function sub(a: string | number, b: string | number): string {
|
||||||
try {
|
try {
|
||||||
return new Big(a).minus(new Big(b)).toString()
|
return new Big(a).minus(new Big(b)).toFixed(2) // ⭐ 保留两位
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
return '0'
|
return '0.00'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,3 +62,9 @@ export function toDateTimeString(date: string | number | Date): string {
|
|||||||
const d = dayjs(toDate(date))
|
const d = dayjs(toDate(date))
|
||||||
return d.isValid() ? d.format('YYYY-MM-DD HH:mm:ss') : ''
|
return d.isValid() ? d.format('YYYY-MM-DD HH:mm:ss') : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isInMonth(date: string, month: string): boolean {
|
||||||
|
// date 形如 "2025-01-12"
|
||||||
|
// month 形如 "2025-01"
|
||||||
|
return dayjs(date).format('YYYY-MM') === month
|
||||||
|
}
|
||||||
@@ -1,179 +1,143 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>记账弹出示例</title>
|
<title>家庭记账列表</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
background-color: rgba(0,0,0,0.3);
|
background: #f9f9f9;
|
||||||
|
margin: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 弹出层 */
|
.record-list {
|
||||||
.drawer {
|
max-width: 600px;
|
||||||
position: fixed;
|
margin: auto;
|
||||||
bottom: 0;
|
}
|
||||||
left: 0;
|
|
||||||
right: 0;
|
.record {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 15px;
|
||||||
|
margin-bottom: 8px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-top-left-radius: 16px;
|
border-radius: 8px;
|
||||||
border-top-right-radius: 16px;
|
position: relative;
|
||||||
padding: 16px;
|
transition: background 0.2s;
|
||||||
max-height: 80%;
|
cursor: default;
|
||||||
overflow-y: auto;
|
|
||||||
box-shadow: 0 -4px 12px rgba(0,0,0,0.2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 收入/支出切换 */
|
.record:hover {
|
||||||
.type-switch {
|
background: #f2f2f2;
|
||||||
display: flex;
|
|
||||||
background: #f0f0f0;
|
|
||||||
border-radius: 12px;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
}
|
||||||
.type-switch div {
|
|
||||||
|
.category-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #eee;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
|
||||||
padding: 8px 0;
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
.type-switch div.active {
|
|
||||||
background-color: #ff9f1c;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 子分类横向滚动 */
|
|
||||||
.sub-categories {
|
|
||||||
display: flex;
|
|
||||||
overflow-x: auto;
|
|
||||||
gap: 12px;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
.sub-category {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
width: 64px;
|
|
||||||
height: 64px;
|
|
||||||
background: #fef6e4;
|
|
||||||
border-radius: 12px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.sub-category.active {
|
|
||||||
background-color: #ff9f1c;
|
|
||||||
color: #fff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 输入框 */
|
.name {
|
||||||
.input-group {
|
font-weight: 600;
|
||||||
margin-bottom: 16px;
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
}
|
}
|
||||||
.input-group label {
|
|
||||||
|
.remark {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
display: none;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record:hover .remark {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
}
|
||||||
.input-group input {
|
|
||||||
width: 100%;
|
.right {
|
||||||
padding: 8px;
|
display: flex;
|
||||||
border-radius: 8px;
|
align-items: center;
|
||||||
border: 1px solid #ddd;
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.amount {
|
||||||
|
font-weight: 600;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 保存按钮 */
|
.amount.income {
|
||||||
.btn-save {
|
color: green;
|
||||||
width: 100%;
|
}
|
||||||
padding: 12px;
|
|
||||||
background-color: #ff9f1c;
|
.amount.expense {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-avatar {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #2196f3;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 16px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
display: flex;
|
||||||
border: none;
|
align-items: center;
|
||||||
border-radius: 12px;
|
justify-content: center;
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="drawer">
|
<div class="record-list">
|
||||||
<!-- 收入/支出切换 -->
|
<div class="record">
|
||||||
<div class="type-switch">
|
<div class="category-icon">🛒</div>
|
||||||
<div class="active" data-type="income">收入</div>
|
<div class="info">
|
||||||
<div data-type="expense">支出</div>
|
<div class="name">购物</div>
|
||||||
|
<div class="remark">买菜和日用品</div>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="amount expense">-50.00</div>
|
||||||
|
<div class="member-avatar">爸</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 子分类 -->
|
<div class="record">
|
||||||
<div class="sub-categories" id="subCategories">
|
<div class="category-icon">🍔</div>
|
||||||
<div class="sub-category active" data-id="1">餐饮</div>
|
<div class="info">
|
||||||
<div class="sub-category" data-id="2">交通</div>
|
<div class="name">午餐</div>
|
||||||
<div class="sub-category" data-id="3">购物</div>
|
<div class="remark">外卖订单</div>
|
||||||
<div class="sub-category" data-id="4">娱乐</div>
|
</div>
|
||||||
<div class="sub-category" data-id="5">工资</div>
|
<div class="right">
|
||||||
<div class="sub-category" data-id="6">兼职</div>
|
<div class="amount expense">-30.00</div>
|
||||||
|
<div class="member-avatar">妈</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 输入金额 -->
|
<div class="record">
|
||||||
<div class="input-group">
|
<div class="category-icon">💰</div>
|
||||||
<label>金额</label>
|
<div class="info">
|
||||||
<input type="number" placeholder="请输入金额">
|
<div class="name">工资</div>
|
||||||
|
<div class="remark">11月工资到账</div>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="amount income">+5000.00</div>
|
||||||
|
<div class="member-avatar">我</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 输入备注 -->
|
|
||||||
<div class="input-group">
|
|
||||||
<label>备注</label>
|
|
||||||
<input type="text" placeholder="输入备注">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 保存按钮 -->
|
|
||||||
<button class="btn-save">保存</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
// 收入/支出切换
|
|
||||||
const typeSwitch = document.querySelectorAll('.type-switch div');
|
|
||||||
typeSwitch.forEach(item => {
|
|
||||||
item.addEventListener('click', () => {
|
|
||||||
typeSwitch.forEach(i => i.classList.remove('active'));
|
|
||||||
item.classList.add('active');
|
|
||||||
// 可在此刷新子分类
|
|
||||||
console.log('切换类型:', item.dataset.type);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 子分类选择
|
|
||||||
const subCategories = document.querySelectorAll('.sub-category');
|
|
||||||
subCategories.forEach(item => {
|
|
||||||
item.addEventListener('click', () => {
|
|
||||||
subCategories.forEach(i => i.classList.remove('active'));
|
|
||||||
item.classList.add('active');
|
|
||||||
console.log('选择子分类:', item.textContent);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 保存按钮
|
|
||||||
document.querySelector('.btn-save').addEventListener('click', () => {
|
|
||||||
const type = document.querySelector('.type-switch div.active').dataset.type;
|
|
||||||
const category = document.querySelector('.sub-category.active').textContent;
|
|
||||||
const amount = document.querySelectorAll('input')[0].value;
|
|
||||||
const remark = document.querySelectorAll('input')[1].value;
|
|
||||||
console.log({ type, category, amount, remark });
|
|
||||||
alert('保存成功!');
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
89
|
|
||||||
@@ -111,8 +111,8 @@ func queryMoneyRecords(c *router.Context) error {
|
|||||||
if dayDataI == nil {
|
if dayDataI == nil {
|
||||||
dayData = mapx.New().
|
dayData = mapx.New().
|
||||||
Set("records", mapx.NewArr()).
|
Set("records", mapx.NewArr()).
|
||||||
Set("income", decimal.NewFromInt(0).String()).
|
Set("income", "0.00").
|
||||||
Set("expense", decimal.NewFromInt(0).String())
|
Set("expense", "0.00")
|
||||||
} else {
|
} else {
|
||||||
dayData = dayDataI.(mapx.M)
|
dayData = dayDataI.(mapx.M)
|
||||||
}
|
}
|
||||||
@@ -132,16 +132,17 @@ func queryMoneyRecords(c *router.Context) error {
|
|||||||
dayIncome, _ := decimal.NewFromString(dayData.GetString("income"))
|
dayIncome, _ := decimal.NewFromString(dayData.GetString("income"))
|
||||||
dayExpense, _ := decimal.NewFromString(dayData.GetString("expense"))
|
dayExpense, _ := decimal.NewFromString(dayData.GetString("expense"))
|
||||||
|
|
||||||
if categoryType == 0 {
|
if categoryType == 1 {
|
||||||
dayIncome = dayIncome.Add(amount)
|
dayIncome = dayIncome.Add(amount)
|
||||||
totalIncome = totalIncome.Add(amount)
|
totalIncome = totalIncome.Add(amount)
|
||||||
} else if categoryType == 1 {
|
} else if categoryType == 0 {
|
||||||
dayExpense = dayExpense.Add(amount)
|
dayExpense = dayExpense.Add(amount)
|
||||||
totalExpense = totalExpense.Add(amount)
|
totalExpense = totalExpense.Add(amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
dayData.Set("income", dayIncome.String())
|
// ⭐ 保留两位小数
|
||||||
dayData.Set("expense", dayExpense.String())
|
dayData.Set("income", dayIncome.Round(2).StringFixed(2))
|
||||||
|
dayData.Set("expense", dayExpense.Round(2).StringFixed(2))
|
||||||
|
|
||||||
grouped.Set(day, dayData)
|
grouped.Set(day, dayData)
|
||||||
}
|
}
|
||||||
@@ -152,7 +153,7 @@ func queryMoneyRecords(c *router.Context) error {
|
|||||||
dates = append(dates, k)
|
dates = append(dates, k)
|
||||||
}
|
}
|
||||||
sort.Slice(dates, func(i, j int) bool {
|
sort.Slice(dates, func(i, j int) bool {
|
||||||
return dates[i] > dates[j] // 倒序
|
return dates[i] > dates[j]
|
||||||
})
|
})
|
||||||
|
|
||||||
// 构建最终 records 数组
|
// 构建最终 records 数组
|
||||||
@@ -166,10 +167,11 @@ func queryMoneyRecords(c *router.Context) error {
|
|||||||
Set("records", dayData.GetArray("records")))
|
Set("records", dayData.GetArray("records")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ⭐ 最终总收入/支出保留两位小数
|
||||||
result := mapx.New().
|
result := mapx.New().
|
||||||
Set("records", recordsArr).
|
Set("records", recordsArr).
|
||||||
Set("total_income", totalIncome.String()).
|
Set("total_income", totalIncome.Round(2).StringFixed(2)).
|
||||||
Set("total_expense", totalExpense.String())
|
Set("total_expense", totalExpense.Round(2).StringFixed(2))
|
||||||
|
|
||||||
return response.Success(c).Data(result).Send()
|
return response.Success(c).Data(result).Send()
|
||||||
}
|
}
|
||||||
@@ -195,9 +197,9 @@ func getUserCategory(c *router.Context) error {
|
|||||||
|
|
||||||
for _, cat := range userCategories {
|
for _, cat := range userCategories {
|
||||||
t := cat.GetInt("type")
|
t := cat.GetInt("type")
|
||||||
if t == 0 {
|
if t == 1 {
|
||||||
result["income"] = append(result["income"], cat)
|
result["income"] = append(result["income"], cat)
|
||||||
} else if t == 1 {
|
} else if t == 0 {
|
||||||
result["expense"] = append(result["expense"], cat)
|
result["expense"] = append(result["expense"], cat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,13 +303,10 @@ func deleteMoneyRecord(c *router.Context) error {
|
|||||||
}
|
}
|
||||||
recordId := bodyData.GetInt64("id")
|
recordId := bodyData.GetInt64("id")
|
||||||
|
|
||||||
deleteOne, err := db.DeleteOne("money_record", "id", recordId)
|
_, err = db.DeleteOne("money_record", "id", recordId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.AddError(err)
|
return c.AddError(err)
|
||||||
}
|
}
|
||||||
if deleteOne != 1 {
|
|
||||||
return response.Fail(c).Message("删除失败").Send()
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.Success(c).Message("删除成功").Send()
|
return response.Success(c).Message("删除成功").Send()
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user