diff --git a/404.svg b/404.svg new file mode 100644 index 00000000..d79b7a22 --- /dev/null +++ b/404.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/code/base-project/base-app/iconfont.json b/code/base-project/base-app/iconfont.json index 38164f1e..fe2e29e8 100644 --- a/code/base-project/base-app/iconfont.json +++ b/code/base-project/base-app/iconfont.json @@ -1,5 +1,5 @@ { - "symbol_url": "//at.alicdn.com/t/c/font_5056764_h6glhbjob2.js", + "symbol_url": "//at.alicdn.com/t/c/font_5056764_r43lrs790nk.js", "use_typescript": true, "save_dir": "./src/components/iconfont", "trim_icon_prefix": "icon", diff --git a/code/base-project/base-app/metro.config.js b/code/base-project/base-app/metro.config.js index 070adbc9..a12614fd 100644 --- a/code/base-project/base-app/metro.config.js +++ b/code/base-project/base-app/metro.config.js @@ -5,9 +5,16 @@ const { withNativeWind } = require('nativewind/metro') /** @type {import('expo/metro-config').MetroConfig} */ const config = getDefaultConfig(__dirname) +config.transformer = { + ...config.transformer, + babelTransformerPath: require.resolve('react-native-svg-transformer/expo'), +} + config.resolver = { ...config.resolver, unstable_enablePackageExports: true, + assetExts: config.resolver.assetExts.filter(ext => ext !== 'svg'), + sourceExts: [...config.resolver.sourceExts, 'svg'], } module.exports = withNativeWind(config, { input: './src/styles/global.css' }) diff --git a/code/base-project/base-app/package.json b/code/base-project/base-app/package.json index 4893d85b..dd14cb17 100644 --- a/code/base-project/base-app/package.json +++ b/code/base-project/base-app/package.json @@ -18,6 +18,7 @@ "@react-native-async-storage/async-storage": "2.2.0", "@react-native-community/datetimepicker": "8.4.4", "@react-native-segmented-control/segmented-control": "2.5.7", + "@yz1311/react-native-wheel-picker": "^0.4.5", "alova": "^3.3.4", "axios": "^1.13.2", "big.js": "^7.0.1", @@ -32,22 +33,22 @@ "expo-splash-screen": "~31.0.10", "expo-status-bar": "~3.0.8", "lucide-react-native": "^0.510.0", + "moment": "^2.30.1", "nativewind": "^4.2.1", "react": "19.1.0", "react-dom": "19.1.0", "react-native": "0.81.5", "react-native-css-interop": "^0.2.1", - "react-native-dates-picker": "^0.2.0", - "react-native-drawer-layout": "^4.2.0", "react-native-gesture-handler": "~2.28.0", "react-native-keyboard-controller": "1.18.5", - "react-native-modal-datetime-picker": "^18.0.0", + "react-native-modal": "14.0.0-rc.1", "react-native-reanimated": "~4.1.3", "react-native-safe-area-context": "~5.6.1", "react-native-screens": "~4.16.0", "react-native-svg": "15.12.1", "react-native-web": "^0.21.0", "react-native-worklets": "0.5.1", + "tailwind-merge": "^3.4.0", "zustand": "^5.0.8" }, "devDependencies": { @@ -57,6 +58,7 @@ "babel-plugin-module-resolver": "^5.0.2", "eslint": "^9.38.0", "react-native-iconfont-cli": "^2.2.4", + "react-native-svg-transformer": "^1.5.2", "tailwindcss": "^3.4.17", "typescript": "~5.9.2" } diff --git a/code/base-project/base-app/pnpm-lock.yaml b/code/base-project/base-app/pnpm-lock.yaml index 28b7893b..c44d298b 100644 --- a/code/base-project/base-app/pnpm-lock.yaml +++ b/code/base-project/base-app/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: '@react-native-segmented-control/segmented-control': specifier: 2.5.7 version: 2.5.7(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + '@yz1311/react-native-wheel-picker': + specifier: ^0.4.5 + version: 0.4.5(deprecated-react-native-prop-types@5.0.0)(moment@2.30.1)(react-native-modal@14.0.0-rc.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)) alova: specifier: ^3.3.4 version: 3.3.4 @@ -74,6 +77,9 @@ importers: lucide-react-native: 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) + moment: + specifier: ^2.30.1 + version: 2.30.1 nativewind: 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)) @@ -89,21 +95,15 @@ importers: react-native-css-interop: 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)) - react-native-dates-picker: - specifier: ^0.2.0 - version: 0.2.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) - react-native-drawer-layout: - specifier: ^4.2.0 - version: 4.2.0(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-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@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-gesture-handler: specifier: ~2.28.0 version: 2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-keyboard-controller: specifier: 1.18.5 version: 1.18.5(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@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) - react-native-modal-datetime-picker: - specifier: ^18.0.0 - version: 18.0.0(@react-native-community/datetimepicker@8.4.4(expo@54.0.23)(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-native-modal: + specifier: 14.0.0-rc.1 + version: 14.0.0-rc.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-reanimated: specifier: ~4.1.3 version: 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) @@ -122,6 +122,9 @@ importers: react-native-worklets: specifier: 0.5.1 version: 0.5.1(@babel/core@7.28.5)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + tailwind-merge: + specifier: ^3.4.0 + version: 3.4.0 zustand: specifier: ^5.0.8 version: 5.0.8(@types/react@19.1.17)(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0)) @@ -144,6 +147,9 @@ importers: react-native-iconfont-cli: 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) + react-native-svg-transformer: + 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) tailwindcss: specifier: ^3.4.17 version: 3.4.18(yaml@2.8.1) @@ -1676,6 +1682,9 @@ packages: resolution: {integrity: sha512-fB7M1CMOCIUudTRuj7kzxIBTVw2KXnsgbQ6+4cbqSxo8NmRRhA0Ul4ZUzZj3rFd3VznTL4Brmocv1oiN0bWZ8w==} engines: {node: '>= 20.19.4'} + '@react-native/normalize-colors@0.73.2': + resolution: {integrity: sha512-bRBcb2T+I88aG74LMVHaKms2p/T8aQd8+BZ7LuuzXlRfog1bMWWn/C5i0HVuvW4RPtXQYgIlGiXVDy9Ir1So/w==} + '@react-native/normalize-colors@0.74.89': resolution: {integrity: sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==} @@ -2024,9 +2033,87 @@ packages: peerDependencies: eslint: '>=9.0.0' + '@svgr/babel-plugin-add-jsx-attribute@8.0.0': + resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0': + resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0': + resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0': + resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0': + resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0': + resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0': + resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-svg-component@8.0.0': + resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} + engines: {node: '>=12'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-preset@8.1.0': + resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/core@8.1.0': + resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} + engines: {node: '>=14'} + + '@svgr/hast-util-to-babel-ast@8.0.0': + resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} + engines: {node: '>=14'} + + '@svgr/plugin-jsx@8.1.0': + resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + + '@svgr/plugin-svgo@8.1.0': + resolution: {integrity: sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + '@swc/helpers@0.5.17': resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + '@trysound/sax@0.2.0': + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -2192,6 +2279,14 @@ packages: resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} engines: {node: '>=10.0.0'} + '@yz1311/react-native-wheel-picker@0.4.5': + resolution: {integrity: sha512-07ga/fYdgHYI3JTAd+ntaXcJ1D3VxbgaqCPxABjxigehmFYD3VpBbMMVRhxmZC3oVnpedc+SKJXHTNwGtLriCQ==} + peerDependencies: + deprecated-react-native-prop-types: '*' + moment: '*' + react-native: '*' + react-native-modal: '*' + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -2620,6 +2715,15 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + cross-fetch@3.2.0: resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} @@ -2641,6 +2745,14 @@ packages: resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} engines: {node: '>=8.0.0'} + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + css-what@6.2.2: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} @@ -2650,6 +2762,10 @@ packages: engines: {node: '>=4'} hasBin: true + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + csstype@3.2.0: resolution: {integrity: sha512-si++xzRAY9iPp60roQiFta7OFbhrgvcthrhlNAGeQptSY25uJjkfUV8OArC3KLocB8JT8ohz+qgxWCmz8RhjIg==} @@ -2725,6 +2841,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + deprecated-react-native-prop-types@5.0.0: + resolution: {integrity: sha512-cIK8KYiiGVOFsKdPMmm1L3tA/Gl+JopXL6F5+C7x39MyPsQYnP57Im/D6bNUzcborD7fcMwiwZqcBdBXXZucYQ==} + engines: {node: '>=18'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2774,6 +2894,9 @@ packages: domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dotenv-expand@11.0.7: resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} engines: {node: '>=12'} @@ -2825,6 +2948,9 @@ packages: resolution: {integrity: sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA==} engines: {node: '>=8'} + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + error-stack-parser@2.1.4: resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} @@ -3536,6 +3662,9 @@ packages: invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-arrayish@0.3.4: resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} @@ -3671,6 +3800,9 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -3770,56 +3902,48 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-gnu@1.30.2: resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] lightningcss-linux-arm64-musl@1.27.0: resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] lightningcss-linux-x64-gnu@1.27.0: resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] lightningcss-linux-x64-musl@1.27.0: resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] lightningcss-win32-arm64-msvc@1.27.0: resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==} @@ -3899,6 +4023,9 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -3967,6 +4094,12 @@ packages: mdn-data@2.0.14: resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} @@ -4250,6 +4383,9 @@ packages: mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -4288,6 +4424,9 @@ packages: nested-error-stacks@2.0.1: resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==} + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -4416,6 +4555,10 @@ packages: parse-imports-exports@0.2.4: resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + parse-png@2.1.0: resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} engines: {node: '>=10'} @@ -4427,6 +4570,9 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + path-dirname@1.0.2: + resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} + path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -4450,6 +4596,10 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -4652,6 +4802,9 @@ packages: react-is@19.2.0: resolution: {integrity: sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==} + react-native-animatable@1.4.0: + resolution: {integrity: sha512-DZwaDVWm2NBvBxf7I0wXKXLKb/TxDnkV53sWhCvei1pRyTX3MVFpkvdYBknNBqPrxYuAIlPxEp7gJOidIauUkw==} + react-native-css-interop@0.2.1: resolution: {integrity: sha512-B88f5rIymJXmy1sNC/MhTkb3xxBej1KkuAt7TiT9iM7oXz3RM8Bn+7GUrfR02TvSgKm4cg2XiSuLEKYfKwNsjA==} engines: {node: '>=18'} @@ -4668,21 +4821,6 @@ packages: react-native-svg: optional: true - react-native-dates-picker@0.2.0: - resolution: {integrity: sha512-dO7HGami3fhKa/WVtd5jj0xfekbNJZzka++4+0pBUW8br2/t9YzyJ7DYPcZ7vGdRy6bw/qkBG6EASRq8DJP/5Q==} - engines: {node: '>= 16.0.0'} - peerDependencies: - react: '>=17.0.0' - react-native: '*' - - react-native-drawer-layout@4.2.0: - resolution: {integrity: sha512-XFGK5RMcVhEqr2F4iH/cTXrcTm1uK3gIBNFPqHNO7rCXuXZTPBbQYA5yc9/Lqgw2KNQ3sAeHKvW6/WoTURo/eA==} - peerDependencies: - react: '>= 18.2.0' - react-native: '*' - react-native-gesture-handler: '>= 2.0.0' - react-native-reanimated: '>= 2.0.0' - react-native-gesture-handler@2.28.0: resolution: {integrity: sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==} peerDependencies: @@ -4710,11 +4848,11 @@ packages: react-native: '*' react-native-reanimated: '>=3.0.0' - react-native-modal-datetime-picker@18.0.0: - resolution: {integrity: sha512-0jdvhhraZQlRACwr7pM6vmZ2kxgzJ4CpnmV6J3TVA6MrXMXK6Zo/upRBKkRp0+fTOiKuNblzesA2U59rYo6SGA==} + react-native-modal@14.0.0-rc.1: + resolution: {integrity: sha512-v5pvGyx1FlmBzdHyPqBsYQyS2mIJhVmuXyNo5EarIzxicKhuoul6XasXMviGcXboEUT0dTYWs88/VendojPiVw==} peerDependencies: - '@react-native-community/datetimepicker': '>=6.7.0' - react-native: '>=0.65.0' + react: '*' + react-native: '>=0.70.0' react-native-reanimated@4.1.5: resolution: {integrity: sha512-UA6VUbxwhRjEw2gSNrvhkusUq3upfD3Cv+AnB07V+kC8kpvwRVI+ivwY95ePbWNFkFpP+Y2Sdw1WHpHWEV+P2Q==} @@ -4736,6 +4874,12 @@ packages: react: '*' react-native: '*' + react-native-svg-transformer@1.5.2: + resolution: {integrity: sha512-eW4hOtrd30s4SRdN4X1XYxTCu1czsxDGQKmfQ3RFbZMN5yw4ZmiKGGr+lXbQW4uDGZvSoGd9FHL1f+rgGoKg8Q==} + peerDependencies: + react-native: '>=0.59.0' + react-native-svg: '>=12.0.0' + react-native-svg@15.12.1: resolution: {integrity: sha512-vCuZJDf8a5aNC2dlMovEv4Z0jjEUET53lm/iILFnFewa15b4atjVxU6Wirm6O9y6dEsdjDZVD7Q3QM4T1wlI8g==} peerDependencies: @@ -5014,6 +5158,9 @@ packages: resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==} engines: {node: '>=8.0.0'} + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -5135,6 +5282,14 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svg-parser@2.0.4: + resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + + svgo@3.3.2: + resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} + engines: {node: '>=14.0.0'} + hasBin: true + synckit@0.11.11: resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -5142,6 +5297,9 @@ packages: tailwind-merge@1.14.0: resolution: {integrity: sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ==} + tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + tailwind-variants@0.1.20: resolution: {integrity: sha512-AMh7x313t/V+eTySKB0Dal08RHY7ggYK0MSn/ad8wKWOrDUIzyiWNayRUm2PIJ4VRkvRnfNuyRuKbLV3EN+ewQ==} engines: {node: '>=16.x', pnpm: '>=7.x'} @@ -7770,6 +7928,8 @@ snapshots: '@react-native/js-polyfills@0.81.5': {} + '@react-native/normalize-colors@0.73.2': {} + '@react-native/normalize-colors@0.74.89': {} '@react-native/normalize-colors@0.81.5': {} @@ -8240,10 +8400,91 @@ snapshots: estraverse: 5.3.0 picomatch: 4.0.3 + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + + '@svgr/babel-preset@8.1.0(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.5) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.5) + + '@svgr/core@8.1.0(typescript@5.9.3)': + dependencies: + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + camelcase: 6.3.0 + cosmiconfig: 8.3.6(typescript@5.9.3) + snake-case: 3.0.4 + transitivePeerDependencies: + - supports-color + - typescript + + '@svgr/hast-util-to-babel-ast@8.0.0': + dependencies: + '@babel/types': 7.28.5 + entities: 4.5.0 + + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))': + dependencies: + '@babel/core': 7.28.5 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.5) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/hast-util-to-babel-ast': 8.0.0 + svg-parser: 2.0.4 + transitivePeerDependencies: + - supports-color + + '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + '@svgr/core': 8.1.0(typescript@5.9.3) + cosmiconfig: 8.3.6(typescript@5.9.3) + deepmerge: 4.3.1 + svgo: 3.3.2 + transitivePeerDependencies: + - typescript + '@swc/helpers@0.5.17': dependencies: tslib: 2.8.1 + '@trysound/sax@0.2.0': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.28.5 @@ -8466,6 +8707,14 @@ snapshots: '@xmldom/xmldom@0.8.11': {} + '@yz1311/react-native-wheel-picker@0.4.5(deprecated-react-native-prop-types@5.0.0)(moment@2.30.1)(react-native-modal@14.0.0-rc.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))': + dependencies: + deprecated-react-native-prop-types: 5.0.0 + moment: 2.30.1 + prop-types: 15.8.1 + react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) + react-native-modal: 14.0.0-rc.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -8944,6 +9193,15 @@ snapshots: core-util-is@1.0.3: {} + cosmiconfig@8.3.6(typescript@5.9.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.9.3 + cross-fetch@3.2.0: dependencies: node-fetch: 2.7.0 @@ -8975,10 +9233,24 @@ snapshots: mdn-data: 2.0.14 source-map: 0.6.1 + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@2.3.1: + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.1 + css-what@6.2.2: {} cssesc@3.0.0: {} + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + csstype@3.2.0: {} dayjs@1.11.19: {} @@ -9023,6 +9295,12 @@ snapshots: depd@2.0.0: {} + deprecated-react-native-prop-types@5.0.0: + dependencies: + '@react-native/normalize-colors': 0.73.2 + invariant: 2.2.4 + prop-types: 15.8.1 + dequal@2.0.3: {} destroy@1.2.0: {} @@ -9066,6 +9344,11 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + dotenv-expand@11.0.7: dependencies: dotenv: 16.4.7 @@ -9103,6 +9386,10 @@ snapshots: env-editor@0.4.2: {} + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + error-stack-parser@2.1.4: dependencies: stackframe: 1.3.4 @@ -9924,6 +10211,8 @@ snapshots: dependencies: loose-envify: 1.4.0 + is-arrayish@0.2.1: {} + is-arrayish@0.3.4: {} is-binary-path@2.1.0: @@ -10075,6 +10364,8 @@ snapshots: json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -10251,6 +10542,10 @@ snapshots: dependencies: js-tokens: 4.0.0 + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + lru-cache@10.4.3: {} lru-cache@5.1.1: @@ -10392,6 +10687,10 @@ snapshots: mdn-data@2.0.14: {} + mdn-data@2.0.28: {} + + mdn-data@2.0.30: {} + memoize-one@5.2.1: {} memoize-one@6.0.0: {} @@ -11004,6 +11303,8 @@ snapshots: pkg-types: 1.3.1 ufo: 1.6.1 + moment@2.30.1: {} + ms@2.0.0: {} ms@2.1.3: {} @@ -11040,6 +11341,11 @@ snapshots: nested-error-stacks@2.0.1: {} + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 @@ -11162,6 +11468,13 @@ snapshots: dependencies: parse-statements: 1.0.11 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + parse-png@2.1.0: dependencies: pngjs: 3.4.0 @@ -11170,6 +11483,8 @@ snapshots: parseurl@1.3.3: {} + path-dirname@1.0.2: {} + path-exists@3.0.0: {} path-exists@4.0.0: {} @@ -11185,6 +11500,8 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-type@4.0.0: {} + pathe@2.0.3: {} picocolors@1.1.1: {} @@ -11410,6 +11727,10 @@ snapshots: react-is@19.2.0: {} + react-native-animatable@1.4.0: + dependencies: + 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)): dependencies: '@babel/helper-module-imports': 7.27.1 @@ -11428,21 +11749,6 @@ snapshots: transitivePeerDependencies: - supports-color - react-native-dates-picker@0.2.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): - dependencies: - dayjs: 1.11.19 - react: 19.1.0 - react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) - - react-native-drawer-layout@4.2.0(react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-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@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): - dependencies: - color: 4.2.3 - react: 19.1.0 - react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) - react-native-gesture-handler: 2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) - react-native-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) - use-latest-callback: 0.2.6(react@19.1.0) - react-native-gesture-handler@2.28.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: '@egjs/hammerjs': 2.0.17 @@ -11478,11 +11784,11 @@ 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-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-modal-datetime-picker@18.0.0(@react-native-community/datetimepicker@8.4.4(expo@54.0.23)(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-native-modal@14.0.0-rc.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: - '@react-native-community/datetimepicker': 8.4.4(expo@54.0.23)(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) - prop-types: 15.8.1 + react: 19.1.0 react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) + react-native-animatable: 1.4.0 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): dependencies: @@ -11506,6 +11812,18 @@ 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) 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): + dependencies: + '@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) + 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-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) + transitivePeerDependencies: + - supports-color + - 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): dependencies: css-select: 5.2.2 @@ -11856,6 +12174,11 @@ snapshots: slugify@1.6.6: {} + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -11961,12 +12284,26 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + svg-parser@2.0.4: {} + + svgo@3.3.2: + dependencies: + '@trysound/sax': 0.2.0 + commander: 7.2.0 + css-select: 5.2.2 + css-tree: 2.3.1 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + synckit@0.11.11: dependencies: '@pkgr/core': 0.2.9 tailwind-merge@1.14.0: {} + tailwind-merge@3.4.0: {} + tailwind-variants@0.1.20(tailwindcss@3.4.18(yaml@2.8.1)): dependencies: tailwind-merge: 1.14.0 diff --git a/code/base-project/base-app/src/app/(tabs)/chat.tsx b/code/base-project/base-app/src/app/(tabs)/chat.tsx index d09b0503..bc7b3503 100644 --- a/code/base-project/base-app/src/app/(tabs)/chat.tsx +++ b/code/base-project/base-app/src/app/(tabs)/chat.tsx @@ -1,48 +1,39 @@ -import dayjs from 'dayjs' -// DemoADatePicker.tsx -import React, { useState } from 'react' -import { Button, ScrollView, StyleSheet } from 'react-native' -import { ADateTimeDrawer } from '@/components/common/ao' +import { DatePicker } from '@yz1311/react-native-wheel-picker' +import { useState } from 'react' +import { Button, Text, View } from 'react-native' +import { ADatePicker } from '@/components/common/ao' -export default function DemoADatePicker() { +export default function Chat() { const [show, setShow] = useState(false) - const [date, setDate] = useState(dayjs()) return ( - - { - console.log(val) - }} - onClose={() => { - setShow(false) - }} - /> - - + <> + + + {/* { + setShow(false) + }} + /> */} + + { + setShow(false) + }} + onClose={() => { + setShow(false) + }} + /> + + + ) } - -const styles = StyleSheet.create({ - container: { - padding: 20, - }, - label: { - marginTop: 20, - fontSize: 16, - fontWeight: 'bold', - }, - result: { - marginVertical: 5, - fontSize: 14, - color: '#333', - }, -}) diff --git a/code/base-project/base-app/src/app/(tabs)/money/components/AddDrawer.tsx b/code/base-project/base-app/src/app/(tabs)/money/components/AddDrawer.tsx index f7ebc183..59c31986 100644 --- a/code/base-project/base-app/src/app/(tabs)/money/components/AddDrawer.tsx +++ b/code/base-project/base-app/src/app/(tabs)/money/components/AddDrawer.tsx @@ -1,10 +1,11 @@ -import type { MoneyCategoryResult } from '@/request/api/money' -import type { MoneyCategory, MoneyRecord } from '@/types/money' +import type { MoneyCategoryItem, QueryMoneyCategoryResult } from '@/types/money/category' +import type { InsertMoneyRecordResult, MoneyRecordBase } from '@/types/money/record' import Big from 'big.js' -import { useEffect, useState } from 'react' -import { ActivityIndicator, Keyboard, Pressable, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native' +import { useEffect, useMemo, useState } from 'react' +import { FlatList, Keyboard, Pressable, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' -import { ADatePicker, ADateTimeDrawer, AInput, LucideIcon } from '@/components/common/ao' +import { AInput, LucideIcon } from '@/components/common/ao' +import { ADatePicker } from '@/components/common/ao/index' import SegmentedTabs from '@/components/common/ao/SegmentedTabs' import { Drawer, @@ -15,7 +16,8 @@ import { } from '@/components/ui/drawer' import { Grid, GridItem } from '@/components/ui/grid' import { useKeyboardHeight } from '@/hooks/useKeyboardHeight' -import { getMoneyCategoryApi, insertMoneyRecordApi } from '@/request/api/money' +import { queryMoneyCategoryApi } from '@/request/api/money/category' +import { insertMoneyRecordApi } from '@/request/api/money/record' import { getCurrentDate } from '@/utils/time' import { toast } from '@/utils/toast' import MoneyCategoryIcon from './MoneyCategoryIcon' @@ -23,6 +25,7 @@ import MoneyCategoryIcon from './MoneyCategoryIcon' interface AddMoneyDrawerProps { isOpen: boolean onClose: () => void + onConfirm?: (result: InsertMoneyRecordResult) => void } interface KeydownItem { @@ -60,6 +63,7 @@ const keys: KeydownItem[] = [ export default function AddMoneyDrawer({ isOpen, onClose, + onConfirm, }: AddMoneyDrawerProps) { const insets = useSafeAreaInsets() // 选择顺序:0 支出 1收入 @@ -73,14 +77,14 @@ export default function AddMoneyDrawer({ // 备注聚焦 const [remarkIsFocused, setRemarkIsFocused] = useState(false) // 分类 - const [categories, setCategories] = useState({ + const [categories, setCategories] = useState({ income: [], expense: [], }) const keyboardHeight = useKeyboardHeight() - const defaultMoneyRecord: MoneyRecord = { + const defaultMoneyRecord: MoneyRecordBase = { id: -1, category_id: -1, user_id: -1, @@ -90,9 +94,9 @@ export default function AddMoneyDrawer({ create_time: '', } - const [moneyRecord, setMoneyRecord] = useState(defaultMoneyRecord) + const [moneyRecord, setMoneyRecord] = useState(defaultMoneyRecord) - function selectCategory(item: MoneyCategory) { + function selectCategory(item: MoneyCategoryItem) { setMoneyRecord({ ...moneyRecord, category_id: item.id, @@ -101,27 +105,19 @@ export default function AddMoneyDrawer({ setShowKeydown(true) } - useEffect(() => { - if (isOpen) { - const fetchCategories = async () => { - try { - const res = await getMoneyCategoryApi() - if (res.isSuccess) { - setCategories(res.data) - } - } - catch (err) { - console.error('获取分类失败', err) - } + const fetchCategories = async () => { + try { + const res = await queryMoneyCategoryApi() + if (res.isSuccess) { + setCategories(res.data) } - fetchCategories() } - }, [isOpen]) - - // 关闭整个drawer处理 - function onMainDrawerClose() { - onClose() + catch (err) { + console.error('获取分类失败', err) + } + } + function resetData() { // 清空键盘记录 setKeydownInput('') // 关闭默认键盘 @@ -134,6 +130,13 @@ export default function AddMoneyDrawer({ setShowDatePicker(false) } + // 关闭整个drawer处理 + function onMainDrawerClose() { + resetData() + + onClose() + } + // 计算过程 const handlePress = (key: string | number) => { setKeydownInput((prev) => { @@ -330,7 +333,9 @@ export default function AddMoneyDrawer({ ...moneyRecord, }).then((res) => { if (res.isSuccess) { - onMainDrawerClose() + resetData() + + onConfirm?.(res.data) } else { toast.show({ @@ -352,7 +357,13 @@ export default function AddMoneyDrawer({ > - + { + fetchCategories() + }} + > 取消 - - - {(() => { - const list = selectedIndex === 1 ? categories.income : categories.expense - const items = list.map((item) => { - const isSelected = moneyRecord.category_id === item.id - return ( - - selectCategory(item)} - > - - - - - {item.name} - - - - ) - }) + {(() => { + const list = selectedIndex === 1 ? categories.income : categories.expense - const remainder = list.length % 4 + // useMemo 生成补全后的列表 + const memoItems = useMemo(() => { + const items = [...list] + const remainder = items.length % 4 if (remainder > 0) { const emptyCount = 4 - remainder for (let i = 0; i < emptyCount; i++) { - items.push() + // 补充占位对象 + items.push({ id: `empty-${i}` } as any) } } - return items - })()} - - + }, [list]) + + return ( + item.id.toString()} + showsVerticalScrollIndicator={false} + renderItem={({ item }) => { + if (!('name' in item)) { + return + } + + const isSelected = moneyRecord.category_id === item.id + return ( + selectCategory(item)} + > + + + + + {item.name} + + + ) + }} + /> + ) + })()} + {showKeydown && ( {remarkIsFocused && keyboardHeight > 220 && ( - + )} )} - { - setMoneyRecord({ - ...moneyRecord, - record_time: val, - }) + + { setShowDatePicker(false) }} - onClose={() => { - setShowDatePicker((false)) + onConfirm={(date) => { + setMoneyRecord({ + ...moneyRecord, + record_time: date, + }) + setShowDatePicker(false) }} /> diff --git a/code/base-project/base-app/src/app/(tabs)/money/components/BalanceCard.tsx b/code/base-project/base-app/src/app/(tabs)/money/components/BalanceCard.tsx deleted file mode 100644 index 220f7b29..00000000 --- a/code/base-project/base-app/src/app/(tabs)/money/components/BalanceCard.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React from 'react' -import { Text, View } from 'react-native' - -function BalanceCard() { - return ( - - - - - 账单已出 - - - {/* 总余额 */} - - 总余额 - - 12,322.67 - - - - {/* 收入 / 支出 */} - - {/* 收入 */} - - - 收入 - ↑ +10% - - - 12,232.00 - - - - {/* 分隔线 */} - - - {/* 支出 */} - - - 支出 - ↓ -20% - - - 1,980.00 - - - - - - ) -} - -export default BalanceCard diff --git a/code/base-project/base-app/src/app/(tabs)/money/components/MoneyCategoryIcon.tsx b/code/base-project/base-app/src/app/(tabs)/money/components/MoneyCategoryIcon.tsx index cc1646af..9fafc0f9 100644 --- a/code/base-project/base-app/src/app/(tabs)/money/components/MoneyCategoryIcon.tsx +++ b/code/base-project/base-app/src/app/(tabs)/money/components/MoneyCategoryIcon.tsx @@ -1,26 +1,5 @@ import React from 'react' -import { - IconGongzi, - IconJiaotong, - IconLingshi, - IconRiyongpin, - IconShouru, - IconShucai, - IconYule, - IconZhichu, -} from '@/components/iconfont' - -const iconMap: Record = { - jiaotong: IconJiaotong, - lingshi: IconLingshi, - riyongpin: IconRiyongpin, - shucai: IconShucai, - yule: IconYule, - gongzi: IconGongzi, -} - -const DefaultIncomeIcon = IconShouru -const DefaultExpenseIcon = IconZhichu +import IconFont from '@/components/iconfont' interface CategoryIconProps { name?: string @@ -36,10 +15,6 @@ export default function MoneyCategoryIcon({ name, size = 24, color, - type = 1, }: CategoryIconProps) { - const IconComponent - = iconMap[name ?? ''] || (type === 0 ? DefaultIncomeIcon : DefaultExpenseIcon) - - return + return } diff --git a/code/base-project/base-app/src/app/(tabs)/money/components/TransactionsList.tsx b/code/base-project/base-app/src/app/(tabs)/money/components/TransactionsList.tsx index 00eb1e67..19709458 100644 --- a/code/base-project/base-app/src/app/(tabs)/money/components/TransactionsList.tsx +++ b/code/base-project/base-app/src/app/(tabs)/money/components/TransactionsList.tsx @@ -1,96 +1,93 @@ +import type { MoneyRecordGroup } from '@/types/money/record' import React from 'react' -import { Text, View } from 'react-native' -import IconFont from '@/components/iconfont' +import { SectionList, Text, View } from 'react-native' +import EmptyState from '@/components/common/EmptyStatus' +import MoneyCategoryIcon from './MoneyCategoryIcon' -interface Transaction { - id: string - description: string - title: string - amount: number - type: 'income' | 'expense' +interface StaticTransactionsProps { + records: MoneyRecordGroup[] } -interface DaySection { - title: string - totalIncome: number - totalExpense: number - data: Transaction[] -} +export default function StaticTransactions({ records }: StaticTransactionsProps) { + if (records.length === 0) { + return ( + + ) + } -// 模拟数据 -const sections: DaySection[] = [ - { - title: '2024/11/10', - totalIncome: 3200, - totalExpense: 1980, - data: [ - { id: '1', title: '午餐', description: '公司食堂', amount: 25, type: 'expense' }, - { id: '2', title: '打车', description: '回家', amount: 40, type: 'expense' }, - { id: '3', title: '工资', description: '11月工资', amount: 3200, type: 'income' }, - ], - }, - { - title: '2024/11/09', - totalIncome: 1200, - totalExpense: 560, - data: [ - { id: '4', title: '早餐', description: '面包牛奶面包牛奶面包牛奶面包牛奶面包牛奶面包牛奶面包牛奶面包牛奶面包牛奶面包牛奶面包牛奶面包牛奶', amount: 15, type: 'expense' }, - { id: '5', title: '电影票', description: '周末电影', amount: 45, type: 'expense' }, - { id: '6', title: '兼职收入', description: '家教', amount: 1200, type: 'income' }, - ], - }, -] + const sections = records.map(group => ({ + title: group.record_time, + totalIncome: group.income, + totalExpense: group.expense, + data: group.records, + })) -export default function StaticTransactions() { return ( - - {sections.map(section => ( - - - - - {section.title} - 星期日 - - - - 收入 ¥ - {section.totalIncome} - - - 支出 ¥ - {section.totalExpense} - - + item.id.toString()} + stickySectionHeadersEnabled={true} + showsVerticalScrollIndicator={false} + renderSectionHeader={({ section }) => ( + + + + {section.title} + + + + { + section.totalIncome !== '0' && ( + + 收入 + {' '} + {section.totalIncome} + + ) + } + { + section.totalExpense !== '0' && ( + + 支出 + {' '} + {section.totalExpense} + + ) + } - - {/* 交易列表 */} - {section.data.map(item => ( - - - - - - - {item.title} - {item.description} - - - - {item.type === 'income' ? '+' : '-'} - ¥ - {item.amount} - - - ))} - ))} - + )} + + renderItem={({ item }) => ( + + + + + + + + {item.category_name} + + + {item.remark && ( + {item.remark} + )} + + + + + {item.category_type === 0 ? '+' : '-'} + {' '} + {item.amount} + + + + )} + /> ) } diff --git a/code/base-project/base-app/src/app/(tabs)/money/index.tsx b/code/base-project/base-app/src/app/(tabs)/money/index.tsx index 38bb68b5..7585c940 100644 --- a/code/base-project/base-app/src/app/(tabs)/money/index.tsx +++ b/code/base-project/base-app/src/app/(tabs)/money/index.tsx @@ -1,129 +1,126 @@ -import type { LayoutChangeEvent } from 'react-native' -import { BlurView } from 'expo-blur' -import { LinearGradient } from 'expo-linear-gradient' -import React, { useEffect, useRef, useState } from 'react' +import type { QueryMoneyRecordsResult } from '@/types/money/record' +import React, { useEffect, useState } from 'react' import { ScrollView, Text, TouchableOpacity, View } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' -import { ADateTimeDrawer, LucideIcon } from '@/components/common/ao' -import { IconJiaotong } from '@/components/iconfont' +import { ADatePicker, LucideIcon } from '@/components/common/ao' import { Fab, FabIcon } from '@/components/ui/fab' -import { Grid, GridItem } from '@/components/ui/grid' import { AddIcon } from '@/components/ui/icon' import { Progress, ProgressFilledTrack } from '@/components/ui/progress' -import { queryMoneyRecordsApi } from '@/request/api/money' +import { queryMoneyRecordsApi } from '@/request/api/money/record' import { getCurrentYearMonth } from '@/utils/time' +import { toast } from '@/utils/toast' import AddMoneyDrawer from './components/AddDrawer' import TransactionsList from './components/TransactionsList' export default function Money() { const [showAddDrawer, setShowAddDrawer] = useState(false) - // 安全高度 const insets = useSafeAreaInsets() - const [gradientHeight, setGradientHeight] = useState(200) - const gridLayout = useRef<{ y: number, height: number } | null>(null) - - const onGridLayout = (e: LayoutChangeEvent) => { - if (!gridLayout.current) { - const { y, height } = e.nativeEvent.layout - gridLayout.current = { y, height } - setGradientHeight(y + height / 2 + 16 + insets.top) - } - } // 日期筛选 const [showDatePicker, setShowDatePicker] = useState(false) const [searchParams, setSearchParams] = useState({ record_time: getCurrentYearMonth(), }) + // 数据 + const [moneyRecords, setMoneyRecords] = useState({ + total_expense: '0', + total_income: '0', + records: [], + }) useEffect(() => { queryMoneyRecordsApi({ record_time: searchParams.record_time, }).then((res) => { - console.log(res.data) + if (res.isSuccess) { + console.log(res.data.records) + setMoneyRecords(res.data) + } + else { + toast.show({ + title: res.message || '查询错误,请稍后再试', + }) + } + }).catch((err) => { + console.log(err) }) }, [searchParams]) return ( - + + + setShowDatePicker(true)} + className="flex flex-row items-center gap-1" + > + {searchParams.record_time} + + - - - - setShowDatePicker(true)} - className="flex flex-row items-center gap-2" - > - {searchParams.record_time} - - - - - - - + + + - - {/* 余额区域 */} - - - 余额 - ↓20% - - 22,313.00 - - - {/* 收入/支出/结余 */} - - - - 收入 - ↑20% + + + + + 余额 + {/* ↓20% */} - 11.0 + 22,313.00 - - - 支出 - ↑20% - - 11.0 - + + + + 收入 + {/* ↑20% */} + + {moneyRecords.total_income} + - - - 结余 - ↑20% - - 11.0 + + + 支出 + {/* ↑20% */} + + {moneyRecords.total_expense} + + {/* + + + 结余 + ↑20% + + 11.0 + */} - {/* 预算进度 */} - - 预算 + + 预算 @@ -132,36 +129,10 @@ export default function Money() { 点击设置 - - - - {[...Array.from({ length: 5 })].map((_, i) => ( - - - 账单 - - ))} - - - - - - - + + { setShowAddDrawer(false) }} + onConfirm={(res) => { + setShowAddDrawer(false) + }} /> - { setSearchParams({ ...searchParams, diff --git a/code/base-project/base-app/src/app/(tabs)/user.tsx b/code/base-project/base-app/src/app/(tabs)/user.tsx index 305f43fe..c39a8855 100644 --- a/code/base-project/base-app/src/app/(tabs)/user.tsx +++ b/code/base-project/base-app/src/app/(tabs)/user.tsx @@ -44,7 +44,7 @@ export default function User() { { - router.replace('/auth') + router.replace('/abc') }} > 跳转到登陆页面 diff --git a/code/base-project/base-app/src/app/+not-found.tsx b/code/base-project/base-app/src/app/+not-found.tsx index 576f9c0f..09023030 100644 --- a/code/base-project/base-app/src/app/+not-found.tsx +++ b/code/base-project/base-app/src/app/+not-found.tsx @@ -1,5 +1,5 @@ import { router, Stack } from 'expo-router' -import { ArrowLeft } from 'lucide-react-native' +import { AButton } from '@/components/common/ao' import EmptyState from '@/components/common/EmptyStatus' export default function NotFound() { @@ -7,12 +7,14 @@ export default function NotFound() { <> router.replace('/money')} + footer={( + router.replace('/')} leftIcon={{ icon: 'ArrowLeft', size: 18, color: '#fff' }}> + 返回应用首页 + + )} /> ) diff --git a/code/base-project/base-app/src/app/_layout.tsx b/code/base-project/base-app/src/app/_layout.tsx index 1162e28c..3a23be4c 100644 --- a/code/base-project/base-app/src/app/_layout.tsx +++ b/code/base-project/base-app/src/app/_layout.tsx @@ -4,9 +4,9 @@ import { useFonts } from 'expo-font' import { Stack, useRouter } from 'expo-router' import * as SplashScreen from 'expo-splash-screen' import { StatusBar } from 'expo-status-bar' -import { RefreshCw } from 'lucide-react-native' import { useEffect } from 'react' import { KeyboardProvider } from 'react-native-keyboard-controller' +import { AButton } from '@/components/common/ao' import EmptyState from '@/components/common/EmptyStatus' import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider' import { useUserStore } from '@/store/user' @@ -18,19 +18,21 @@ import 'react-native-gesture-handler' SplashScreen.preventAutoHideAsync() export const unstable_settings = { - initialRouteName: 'money', // 指向你想默认显示的页面 + initialRouteName: 'money', } export function ErrorBoundary({ error, retry }: ErrorBoundaryProps) { return ( + 再试一下 + + )} /> ) diff --git a/code/base-project/base-app/src/components/common/EmptyStatus.tsx b/code/base-project/base-app/src/components/common/EmptyStatus.tsx index dfedd3e7..f7012074 100644 --- a/code/base-project/base-app/src/components/common/EmptyStatus.tsx +++ b/code/base-project/base-app/src/components/common/EmptyStatus.tsx @@ -1,22 +1,28 @@ -import { Image, ScrollView, Text } from 'react-native' -import { Button, ButtonIcon, ButtonText } from '@/components/ui/button' +import { ScrollView, Text } from 'react-native' +import Empty from '@/static/images/Empty.svg' +import Error from '@/static/images/Error.svg' +import NotFound from '@/static/images/NotFound.svg' interface EmptyStateProps { - image: any - title: string + type?: 'empty' | 'error' | '404' + title?: string description?: string - buttonText: string - buttonIcon?: React.ElementType - onButtonPress: () => void + image?: React.ReactNode + footer?: React.ReactNode +} + +const defaultImages = { + empty: , + error: , + 404: , } export default function EmptyState({ - image, + type = 'empty', title, description, - buttonText, - buttonIcon, - onButtonPress, + image, + footer, }: EmptyStateProps) { return ( - + {/* image 插槽优先 */} + {image ?? defaultImages[type]} - {title} + {title && ( + {title} + )} {description && ( @@ -39,12 +48,7 @@ export default function EmptyState({ )} - + {footer} ) } diff --git a/code/base-project/base-app/src/components/common/ao/Button.tsx b/code/base-project/base-app/src/components/common/ao/Button.tsx index 4973cbc1..2fae814e 100644 --- a/code/base-project/base-app/src/components/common/ao/Button.tsx +++ b/code/base-project/base-app/src/components/common/ao/Button.tsx @@ -1,11 +1,15 @@ +import type { icons } from 'lucide-react-native' import type { ViewStyle } from 'react-native' -// components/ui/CustomButton.tsx +import type { LucideIconProps } from './LucideIcon' import React from 'react' import { ButtonSpinner, ButtonText, Button as NativeButton, } from '@/components/ui/button' +import LucideIcon from './LucideIcon' + +type IconProp = (LucideIconProps & { icon: keyof typeof icons }) | React.ReactNode interface CustomButtonProps { children: React.ReactNode @@ -17,6 +21,9 @@ interface CustomButtonProps { action?: 'primary' | 'secondary' | 'positive' | 'negative' | 'default' variant?: 'solid' | 'outline' | 'link' size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' + + leftIcon?: IconProp + rightIcon?: IconProp } const Button: React.FC = ({ @@ -29,24 +36,51 @@ const Button: React.FC = ({ action = 'primary', variant = 'solid', size = 'md', + leftIcon, + rightIcon, }) => { const isDisabled = disabled || loading + const renderLeftIcon = () => { + if (loading) + return + if (!leftIcon) + return null + + if (React.isValidElement(leftIcon)) { + return {leftIcon} + } + + // 只剩下 LucideIconProps & { icon } + const { icon, ...props } = leftIcon as LucideIconProps & { icon: keyof typeof icons } + return + } + + const renderRightIcon = () => { + if (!rightIcon) + return null + + if (React.isValidElement(rightIcon)) { + return {rightIcon} + } + + const { icon, ...props } = rightIcon as LucideIconProps & { icon: keyof typeof icons } + return + } + return ( - {loading && } + {renderLeftIcon()} {children} + {renderRightIcon()} ) } diff --git a/code/base-project/base-app/src/components/common/ao/DatePicker.tsx b/code/base-project/base-app/src/components/common/ao/DatePicker.tsx index 5a1b12cf..fa59a91d 100644 --- a/code/base-project/base-app/src/components/common/ao/DatePicker.tsx +++ b/code/base-project/base-app/src/components/common/ao/DatePicker.tsx @@ -1,81 +1,108 @@ -import type { DateTimePickerProps } from 'react-native-modal-datetime-picker' +import type { IDatePickerProps } from '@yz1311/react-native-wheel-picker' +import { DatePicker } from '@yz1311/react-native-wheel-picker' import dayjs from 'dayjs' -import customParseFormat from 'dayjs/plugin/customParseFormat' -import React, { useMemo } from 'react' -import DateTimePickerModal from 'react-native-modal-datetime-picker' +import React, { useEffect, useRef, useState } from 'react' +import { Animated, Modal, StyleSheet, TouchableOpacity } from 'react-native' +import { toDate } from '@/utils/time' +// 定义 mode 类型 +export type DatePickerMode = 'year' | 'month' | 'date' | 'time' | 'datetime' -dayjs.extend(customParseFormat) +// 定义 format 类型 +export type DateFormatType = 'YYYY' | 'YYYY-MM' | 'YYYY-MM-DD' | 'HH:mm:ss' | 'YYYY-MM-DD HH:mm:ss' -interface ADatePickerProps extends Omit { - format?: string - onConfirm?: (value: string) => void +interface ADatePickerProps extends Omit { date?: Date | string - is24Hour?: boolean - onCancel?: () => void + show?: boolean + onClose?: () => void + onConfirm?: (value: string) => void + mode?: DatePickerMode + format?: DateFormatType } -export default function DatePicker({ +const defaultFormatMap: Record = { + year: 'YYYY', + month: 'YYYY-MM', + date: 'YYYY-MM-DD', + time: 'HH:mm:ss', + datetime: 'YYYY-MM-DD HH:mm:ss', +} + +export default function ADatePicker({ + date, + show = false, + onClose, + onConfirm, mode = 'date', format, - date, - onConfirm, - is24Hour = true, - onCancel, ...restProps }: ADatePickerProps) { - const parsedDate = useMemo(() => { - if (!date) - return new Date() + const fadeAnim = useRef(new Animated.Value(0)).current + const slideAnim = useRef(new Animated.Value(300)).current + const [visible, setVisible] = useState(show) - if (typeof date === 'string') { - // 支持多种常见日期格式 - const formats = ['YYYY-MM-DD', 'YYYY/MM/DD', 'YYYY-MM-DDTHH:mm:ssZ', 'YYYY/MM/DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss'] - for (const fmt of formats) { - const d = dayjs(date, fmt, true) - if (d.isValid()) - return d.toDate() - } - // fallback: 尝试直接解析 - const d = dayjs(date) - if (d.isValid()) - return d.toDate() - // 仍然不合法就返回当前时间 - return new Date() + // 使用传入 format 或默认 format + const finalFormat = format || defaultFormatMap[mode] + + useEffect(() => { + if (show) { + setVisible(true) + fadeAnim.setValue(0) + slideAnim.setValue(300) + Animated.parallel([ + Animated.timing(fadeAnim, { toValue: 1, duration: 250, useNativeDriver: true }), + Animated.timing(slideAnim, { toValue: 0, duration: 250, useNativeDriver: true }), + ]).start() } + else { + Animated.parallel([ + Animated.timing(fadeAnim, { toValue: 0, duration: 250, useNativeDriver: true }), + Animated.timing(slideAnim, { toValue: 280, duration: 250, useNativeDriver: true }), + ]).start(() => setVisible(false)) + } + }, [show]) - return date - }, [date]) + const handleCancel = () => onClose?.() - const handleConfirm = (selectedDate: Date) => { - const fmt = format || (() => { - switch (mode) { - case 'time': - return 'HH:mm:00' - case 'datetime': - return 'YYYY-MM-DD HH:mm:00' - case 'date': - default: - return 'YYYY-MM-DD' - } - })() - - const localTimeStr = dayjs(selectedDate).format(fmt) - onConfirm?.(localTimeStr) + const handleConfirm = (date: Date) => { + const value = dayjs(date).format(finalFormat) + onConfirm?.(value) } - const handleCancel = () => { - onCancel?.() - } + if (!visible) + return null return ( - + + + + + + + + + ) } + +const styles = StyleSheet.create({ + overlay: { + ...StyleSheet.absoluteFillObject, + backgroundColor: 'rgba(0,0,0,0.5)', + }, + pickerContainer: { + backgroundColor: '#fff', + overflow: 'hidden', + position: 'absolute', + bottom: 0, + width: '100%', + }, +}) diff --git a/code/base-project/base-app/src/components/common/ao/DateTimeDrawer.tsx b/code/base-project/base-app/src/components/common/ao/DateTimeDrawer.tsx deleted file mode 100644 index b4807d83..00000000 --- a/code/base-project/base-app/src/components/common/ao/DateTimeDrawer.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import type { DateType, OrderedDateParts } from 'react-native-dates-picker/lib/typescript/types' -import dayjs from 'dayjs' -import { useEffect, useRef, useState } from 'react' -import { View } from 'react-native' -import DateTimePicker from 'react-native-dates-picker' - -import { Drawer, DrawerBackdrop, DrawerContent, DrawerFooter, DrawerHeader } from '@/components/ui/drawer' -import AButton from './Button' - -type DateWheelMode - = | 'year-month' - | 'year-month-day' - | 'hour-minute-second' - | 'year-month-day-hour-minute-second' - -interface DateDrawerProps { - isOpen?: boolean - defaultDate?: DateType - modeType?: DateWheelMode - onClose?: () => void - onConfirm?: (dateStr: string) => void -} - -const modeColumnsMap: Record = { - 'year-month': ['year', 'month'], - 'year-month-day': ['year', 'month', 'day'], - 'hour-minute-second': ['hour', 'minute', 'second'], - 'year-month-day-hour-minute-second': ['year', 'month', 'day', 'hour', 'minute', 'second'], -} - -const modeFormatMap: Record = { - 'year-month': 'YYYY-MM', - 'year-month-day': 'YYYY-MM-DD', - 'hour-minute-second': 'HH:mm:ss', - 'year-month-day-hour-minute-second': 'YYYY-MM-DD HH:mm:ss', -} - -export default function DateWheelDrawer({ - isOpen, - defaultDate = dayjs(), - onClose, - onConfirm, - modeType = 'year-month-day', -}: DateDrawerProps) { - const columns = modeColumnsMap[modeType] - const format = modeFormatMap[modeType] - - // 当前选择的值 - const [date, setDate] = useState(defaultDate) - // 保存上一次确认的值 - const lastConfirmedRef = useRef(defaultDate) - - // 每次弹窗打开时,把滚轮显示初始化为上一次确认的值 - useEffect(() => { - if (isOpen) { - setDate(lastConfirmedRef.current) - } - }, [isOpen]) - - // 点击取消 - const handleCancel = () => { - onClose?.() - } - - // 点击确认 - const handleConfirm = () => { - console.log("确实") - onClose?.() - lastConfirmedRef.current = date // 保存为上一次确认的值 - - if (onConfirm) { - const formatted = dayjs(date).format(format) - onConfirm(formatted) - } - } - - return ( - - - - - 取消 - 确认 - - - - setDate(params.date)} - /> - - - - - - ) -} diff --git a/code/base-project/base-app/src/components/common/ao/LucideIcon.tsx b/code/base-project/base-app/src/components/common/ao/LucideIcon.tsx index dab815ea..80b6a3ea 100644 --- a/code/base-project/base-app/src/components/common/ao/LucideIcon.tsx +++ b/code/base-project/base-app/src/components/common/ao/LucideIcon.tsx @@ -3,14 +3,15 @@ import { icons } from 'lucide-react-native' import React from 'react' import { Pressable } from 'react-native' -interface LucideIconProps { +export interface LucideIconProps { icon: keyof typeof icons size?: number color?: string strokeWidth?: number onPress?: (event: GestureResponderEvent) => void style?: ViewStyle - clickable?: boolean // 新增参数,是否可点击,默认 true + clickable?: boolean + className?: string } export default function LucideIcon({ @@ -21,6 +22,7 @@ export default function LucideIcon({ onPress, style, clickable = true, + className, }: LucideIconProps) { const IconComponent = icons[icon] @@ -28,12 +30,12 @@ export default function LucideIcon({ return null if (!clickable) { - return + return } // clickable 为 true,包 Pressable return ( - + ) diff --git a/code/base-project/base-app/src/components/common/ao/index.ts b/code/base-project/base-app/src/components/common/ao/index.ts index d78bfd82..b4a5fdce 100644 --- a/code/base-project/base-app/src/components/common/ao/index.ts +++ b/code/base-project/base-app/src/components/common/ao/index.ts @@ -1,7 +1,6 @@ import Button from './Button' import Checkbox from './Checkbox' import DatePicker from './DatePicker' -import DateTimeDrawer from './DateTimeDrawer' import Form, { FormRef } from './Form' import FormItem from './FormItem' import Input from './Input' @@ -11,7 +10,6 @@ export { Button as AButton, Checkbox as ACheckbox, DatePicker as ADatePicker, - DateTimeDrawer as ADateTimeDrawer, Form as AForm, FormItem as AFormItem, FormRef as AFormRef, diff --git a/code/base-project/base-app/src/components/iconfont/IconCanyin.tsx b/code/base-project/base-app/src/components/iconfont/IconCanyin.tsx new file mode 100644 index 00000000..e65c339e --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconCanyin.tsx @@ -0,0 +1,32 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconCanyin: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + ); +}; + +export default React.memo(IconCanyin); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconFushi.tsx b/code/base-project/base-app/src/components/iconfont/IconFushi.tsx new file mode 100644 index 00000000..672694e9 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconFushi.tsx @@ -0,0 +1,36 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconFushi: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + + ); +}; + +export default React.memo(IconFushi); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconGongzi.tsx b/code/base-project/base-app/src/components/iconfont/IconGongzi.tsx index aa76e4ad..a45bafeb 100644 --- a/code/base-project/base-app/src/components/iconfont/IconGongzi.tsx +++ b/code/base-project/base-app/src/components/iconfont/IconGongzi.tsx @@ -1,47 +1,44 @@ -/* tslint:disable */ /* eslint-disable */ +/* tslint:disable */ -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; import { Svg, GProps, Path } from 'react-native-svg'; import { getIconColor } from './helper'; -interface Props extends GProps, ViewProps { +interface Props extends Omit, ViewProps { size?: number; color?: string | string[]; } -let IconGongzi: FunctionComponent = ({ size, color, ...rest }) => { +const IconGongzi: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { return ( + - + ); }; -IconGongzi.defaultProps = { - size: 18, -}; - -IconGongzi = React.memo ? React.memo(IconGongzi) : IconGongzi; - -export default IconGongzi; +export default React.memo(IconGongzi); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconGouwu.tsx b/code/base-project/base-app/src/components/iconfont/IconGouwu.tsx new file mode 100644 index 00000000..c2307b8a --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconGouwu.tsx @@ -0,0 +1,44 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconGouwu: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + + + + ); +}; + +export default React.memo(IconGouwu); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconJianzhi.tsx b/code/base-project/base-app/src/components/iconfont/IconJianzhi.tsx new file mode 100644 index 00000000..4ef868c2 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconJianzhi.tsx @@ -0,0 +1,32 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconJianzhi: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + ); +}; + +export default React.memo(IconJianzhi); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconJiaotong.tsx b/code/base-project/base-app/src/components/iconfont/IconJiaotong.tsx index f9586f34..d4a3449d 100644 --- a/code/base-project/base-app/src/components/iconfont/IconJiaotong.tsx +++ b/code/base-project/base-app/src/components/iconfont/IconJiaotong.tsx @@ -1,123 +1,32 @@ -/* tslint:disable */ /* eslint-disable */ +/* tslint:disable */ -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; import { Svg, GProps, Path } from 'react-native-svg'; import { getIconColor } from './helper'; -interface Props extends GProps, ViewProps { +interface Props extends Omit, ViewProps { size?: number; color?: string | string[]; } -let IconJiaotong: FunctionComponent = ({ size, color, ...rest }) => { +const IconJiaotong: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { return ( + - - - - - - - - - - - - - - - - - - - - - - - + ); }; -IconJiaotong.defaultProps = { - size: 18, -}; - -IconJiaotong = React.memo ? React.memo(IconJiaotong) : IconJiaotong; - -export default IconJiaotong; +export default React.memo(IconJiaotong); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconKuaidi.tsx b/code/base-project/base-app/src/components/iconfont/IconKuaidi.tsx new file mode 100644 index 00000000..cb66fa93 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconKuaidi.tsx @@ -0,0 +1,32 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconKuaidi: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + ); +}; + +export default React.memo(IconKuaidi); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconLijin.tsx b/code/base-project/base-app/src/components/iconfont/IconLijin.tsx new file mode 100644 index 00000000..ed062d09 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconLijin.tsx @@ -0,0 +1,36 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconLijin: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + + ); +}; + +export default React.memo(IconLijin); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconLingshi.tsx b/code/base-project/base-app/src/components/iconfont/IconLingshi.tsx index 921fd1b2..079b565e 100644 --- a/code/base-project/base-app/src/components/iconfont/IconLingshi.tsx +++ b/code/base-project/base-app/src/components/iconfont/IconLingshi.tsx @@ -1,75 +1,32 @@ -/* tslint:disable */ /* eslint-disable */ +/* tslint:disable */ -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; import { Svg, GProps, Path } from 'react-native-svg'; import { getIconColor } from './helper'; -interface Props extends GProps, ViewProps { +interface Props extends Omit, ViewProps { size?: number; color?: string | string[]; } -let IconLingshi: FunctionComponent = ({ size, color, ...rest }) => { +const IconLingshi: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { return ( + - - - - - - - - - - - + ); }; -IconLingshi.defaultProps = { - size: 18, -}; - -IconLingshi = React.memo ? React.memo(IconLingshi) : IconLingshi; - -export default IconLingshi; +export default React.memo(IconLingshi); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconQita.tsx b/code/base-project/base-app/src/components/iconfont/IconQita.tsx new file mode 100644 index 00000000..45256be3 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconQita.tsx @@ -0,0 +1,32 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconQita: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + ); +}; + +export default React.memo(IconQita); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconQq.tsx b/code/base-project/base-app/src/components/iconfont/IconQq.tsx index b5a81e3c..49bb0a15 100644 --- a/code/base-project/base-app/src/components/iconfont/IconQq.tsx +++ b/code/base-project/base-app/src/components/iconfont/IconQq.tsx @@ -1,18 +1,24 @@ -/* tslint:disable */ /* eslint-disable */ +/* tslint:disable */ -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; import { Svg, GProps, Path } from 'react-native-svg'; import { getIconColor } from './helper'; -interface Props extends GProps, ViewProps { +interface Props extends Omit, ViewProps { size?: number; color?: string | string[]; } -let IconQq: FunctionComponent = ({ size, color, ...rest }) => { +const IconQq: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { return ( + = ({ size, color, ...rest }) => { fill={getIconColor(color, 9, '#EB1C26')} /> + ); }; -IconQq.defaultProps = { - size: 18, -}; - -IconQq = React.memo ? React.memo(IconQq) : IconQq; - -export default IconQq; +export default React.memo(IconQq); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconRiyongpin.tsx b/code/base-project/base-app/src/components/iconfont/IconRiyongpin.tsx index d0de3bc7..137dd346 100644 --- a/code/base-project/base-app/src/components/iconfont/IconRiyongpin.tsx +++ b/code/base-project/base-app/src/components/iconfont/IconRiyongpin.tsx @@ -1,59 +1,36 @@ -/* tslint:disable */ /* eslint-disable */ +/* tslint:disable */ -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; import { Svg, GProps, Path } from 'react-native-svg'; import { getIconColor } from './helper'; -interface Props extends GProps, ViewProps { +interface Props extends Omit, ViewProps { size?: number; color?: string | string[]; } -let IconRiyongpin: FunctionComponent = ({ size, color, ...rest }) => { +const IconRiyongpin: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { return ( + - - - - - - + ); }; -IconRiyongpin.defaultProps = { - size: 18, -}; - -IconRiyongpin = React.memo ? React.memo(IconRiyongpin) : IconRiyongpin; - -export default IconRiyongpin; +export default React.memo(IconRiyongpin); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconRuanjian.tsx b/code/base-project/base-app/src/components/iconfont/IconRuanjian.tsx new file mode 100644 index 00000000..863e7dc9 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconRuanjian.tsx @@ -0,0 +1,32 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconRuanjian: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + ); +}; + +export default React.memo(IconRuanjian); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconShezhi.tsx b/code/base-project/base-app/src/components/iconfont/IconShezhi.tsx new file mode 100644 index 00000000..6e4354cd --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconShezhi.tsx @@ -0,0 +1,36 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconShezhi: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + + ); +}; + +export default React.memo(IconShezhi); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconShipin.tsx b/code/base-project/base-app/src/components/iconfont/IconShipin.tsx new file mode 100644 index 00000000..8314435b --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconShipin.tsx @@ -0,0 +1,32 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconShipin: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + ); +}; + +export default React.memo(IconShipin); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconShouru.tsx b/code/base-project/base-app/src/components/iconfont/IconShouru.tsx deleted file mode 100644 index f894577d..00000000 --- a/code/base-project/base-app/src/components/iconfont/IconShouru.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ - -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; -import { Svg, GProps, Path } from 'react-native-svg'; -import { getIconColor } from './helper'; - -interface Props extends GProps, ViewProps { - size?: number; - color?: string | string[]; -} - -let IconShouru: FunctionComponent = ({ size, color, ...rest }) => { - return ( - - - - - - - - - ); -}; - -IconShouru.defaultProps = { - size: 18, -}; - -IconShouru = React.memo ? React.memo(IconShouru) : IconShouru; - -export default IconShouru; diff --git a/code/base-project/base-app/src/components/iconfont/IconShucai.tsx b/code/base-project/base-app/src/components/iconfont/IconShucai.tsx deleted file mode 100644 index a118f8ea..00000000 --- a/code/base-project/base-app/src/components/iconfont/IconShucai.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ - -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; -import { Svg, GProps, Path } from 'react-native-svg'; -import { getIconColor } from './helper'; - -interface Props extends GProps, ViewProps { - size?: number; - color?: string | string[]; -} - -let IconShucai: FunctionComponent = ({ size, color, ...rest }) => { - return ( - - - - - - - - ); -}; - -IconShucai.defaultProps = { - size: 18, -}; - -IconShucai = React.memo ? React.memo(IconShucai) : IconShucai; - -export default IconShucai; diff --git a/code/base-project/base-app/src/components/iconfont/IconTongxun.tsx b/code/base-project/base-app/src/components/iconfont/IconTongxun.tsx new file mode 100644 index 00000000..70cb8bd0 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconTongxun.tsx @@ -0,0 +1,32 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconTongxun: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + ); +}; + +export default React.memo(IconTongxun); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconWeixin.tsx b/code/base-project/base-app/src/components/iconfont/IconWeixin.tsx index a9fd0fb6..5eaf4d38 100644 --- a/code/base-project/base-app/src/components/iconfont/IconWeixin.tsx +++ b/code/base-project/base-app/src/components/iconfont/IconWeixin.tsx @@ -1,18 +1,24 @@ -/* tslint:disable */ /* eslint-disable */ +/* tslint:disable */ -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; import { Svg, GProps, Path } from 'react-native-svg'; import { getIconColor } from './helper'; -interface Props extends GProps, ViewProps { +interface Props extends Omit, ViewProps { size?: number; color?: string | string[]; } -let IconWeixin: FunctionComponent = ({ size, color, ...rest }) => { +const IconWeixin: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { return ( + = ({ size, color, ...rest }) => { fill={getIconColor(color, 1, '#4CBF00')} /> + ); }; -IconWeixin.defaultProps = { - size: 18, -}; - -IconWeixin = React.memo ? React.memo(IconWeixin) : IconWeixin; - -export default IconWeixin; +export default React.memo(IconWeixin); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconWeixiu.tsx b/code/base-project/base-app/src/components/iconfont/IconWeixiu.tsx new file mode 100644 index 00000000..c7ab5b27 --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconWeixiu.tsx @@ -0,0 +1,32 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconWeixiu: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + ); +}; + +export default React.memo(IconWeixiu); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconYule.tsx b/code/base-project/base-app/src/components/iconfont/IconYule.tsx index 3ba09f3f..9a08ef40 100644 --- a/code/base-project/base-app/src/components/iconfont/IconYule.tsx +++ b/code/base-project/base-app/src/components/iconfont/IconYule.tsx @@ -1,71 +1,32 @@ -/* tslint:disable */ /* eslint-disable */ +/* tslint:disable */ -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; import { Svg, GProps, Path } from 'react-native-svg'; import { getIconColor } from './helper'; -interface Props extends GProps, ViewProps { +interface Props extends Omit, ViewProps { size?: number; color?: string | string[]; } -let IconYule: FunctionComponent = ({ size, color, ...rest }) => { +const IconYule: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { return ( + - - - - - - - - - - + ); }; -IconYule.defaultProps = { - size: 18, -}; - -IconYule = React.memo ? React.memo(IconYule) : IconYule; - -export default IconYule; +export default React.memo(IconYule); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconZhichu.tsx b/code/base-project/base-app/src/components/iconfont/IconZhichu.tsx deleted file mode 100644 index fe397bc5..00000000 --- a/code/base-project/base-app/src/components/iconfont/IconZhichu.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ - -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; -import { Svg, GProps, Path } from 'react-native-svg'; -import { getIconColor } from './helper'; - -interface Props extends GProps, ViewProps { - size?: number; - color?: string | string[]; -} - -let IconZhichu: FunctionComponent = ({ size, color, ...rest }) => { - return ( - - - - - - - - - ); -}; - -IconZhichu.defaultProps = { - size: 18, -}; - -IconZhichu = React.memo ? React.memo(IconZhichu) : IconZhichu; - -export default IconZhichu; diff --git a/code/base-project/base-app/src/components/iconfont/IconZhiwen.tsx b/code/base-project/base-app/src/components/iconfont/IconZhiwen.tsx index f5b3a3fc..c4b9b46e 100644 --- a/code/base-project/base-app/src/components/iconfont/IconZhiwen.tsx +++ b/code/base-project/base-app/src/components/iconfont/IconZhiwen.tsx @@ -1,18 +1,24 @@ -/* tslint:disable */ /* eslint-disable */ +/* tslint:disable */ -import React, { FunctionComponent } from 'react'; -import { ViewProps } from 'react-native'; +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; import { Svg, GProps, Path } from 'react-native-svg'; import { getIconColor } from './helper'; -interface Props extends GProps, ViewProps { +interface Props extends Omit, ViewProps { size?: number; color?: string | string[]; } -let IconZhiwen: FunctionComponent = ({ size, color, ...rest }) => { +const IconZhiwen: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { return ( + = ({ size, color, ...rest }) => { fill={getIconColor(color, 3, '#FFBB12')} /> + ); }; -IconZhiwen.defaultProps = { - size: 18, -}; - -IconZhiwen = React.memo ? React.memo(IconZhiwen) : IconZhiwen; - -export default IconZhiwen; +export default React.memo(IconZhiwen); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/IconZhufang.tsx b/code/base-project/base-app/src/components/iconfont/IconZhufang.tsx new file mode 100644 index 00000000..89b9413e --- /dev/null +++ b/code/base-project/base-app/src/components/iconfont/IconZhufang.tsx @@ -0,0 +1,36 @@ +/* eslint-disable */ +/* tslint:disable */ + +import React from 'react'; +import type { FunctionComponent } from 'react'; +import type { ViewProps } from 'react-native'; +import { Svg, GProps, Path } from 'react-native-svg'; +import { getIconColor } from './helper'; + +interface Props extends Omit, ViewProps { + size?: number; + color?: string | string[]; +} + +const IconZhufang: FunctionComponent = ({ + size = 18, + color, + ...rest +}) => { + return ( + + + + + + + ); +}; + +export default React.memo(IconZhufang); \ No newline at end of file diff --git a/code/base-project/base-app/src/components/iconfont/index.tsx b/code/base-project/base-app/src/components/iconfont/index.tsx index 1abb5559..2ebe11de 100644 --- a/code/base-project/base-app/src/components/iconfont/index.tsx +++ b/code/base-project/base-app/src/components/iconfont/index.tsx @@ -4,30 +4,50 @@ import React, { FunctionComponent } from 'react'; import { ViewProps } from 'react-native'; import { GProps } from 'react-native-svg'; -import IconZhichu from './IconZhichu'; -import IconShouru from './IconShouru'; import IconGongzi from './IconGongzi'; -import IconJiaotong from './IconJiaotong'; -import IconShucai from './IconShucai'; -import IconRiyongpin from './IconRiyongpin'; -import IconYule from './IconYule'; +import IconLijin from './IconLijin'; import IconLingshi from './IconLingshi'; +import IconShipin from './IconShipin'; +import IconShezhi from './IconShezhi'; +import IconJianzhi from './IconJianzhi'; +import IconJiaotong from './IconJiaotong'; +import IconTongxun from './IconTongxun'; +import IconGouwu from './IconGouwu'; +import IconCanyin from './IconCanyin'; +import IconZhufang from './IconZhufang'; +import IconWeixiu from './IconWeixiu'; +import IconFushi from './IconFushi'; +import IconRiyongpin from './IconRiyongpin'; +import IconKuaidi from './IconKuaidi'; +import IconQita from './IconQita'; +import IconRuanjian from './IconRuanjian'; +import IconYule from './IconYule'; import IconWeixin from './IconWeixin'; import IconZhiwen from './IconZhiwen'; import IconQq from './IconQq'; -export { default as IconZhichu } from './IconZhichu'; -export { default as IconShouru } from './IconShouru'; export { default as IconGongzi } from './IconGongzi'; -export { default as IconJiaotong } from './IconJiaotong'; -export { default as IconShucai } from './IconShucai'; -export { default as IconRiyongpin } from './IconRiyongpin'; -export { default as IconYule } from './IconYule'; +export { default as IconLijin } from './IconLijin'; export { default as IconLingshi } from './IconLingshi'; +export { default as IconShipin } from './IconShipin'; +export { default as IconShezhi } from './IconShezhi'; +export { default as IconJianzhi } from './IconJianzhi'; +export { default as IconJiaotong } from './IconJiaotong'; +export { default as IconTongxun } from './IconTongxun'; +export { default as IconGouwu } from './IconGouwu'; +export { default as IconCanyin } from './IconCanyin'; +export { default as IconZhufang } from './IconZhufang'; +export { default as IconWeixiu } from './IconWeixiu'; +export { default as IconFushi } from './IconFushi'; +export { default as IconRiyongpin } from './IconRiyongpin'; +export { default as IconKuaidi } from './IconKuaidi'; +export { default as IconQita } from './IconQita'; +export { default as IconRuanjian } from './IconRuanjian'; +export { default as IconYule } from './IconYule'; export { default as IconWeixin } from './IconWeixin'; export { default as IconZhiwen } from './IconZhiwen'; export { default as IconQq } from './IconQq'; -export type IconNames = 'zhichu' | 'shouru' | 'gongzi' | 'jiaotong' | 'shucai' | 'riyongpin' | 'yule' | 'lingshi' | 'weixin' | 'zhiwen' | 'QQ'; +export type IconNames = 'gongzi' | 'lijin' | 'lingshi' | 'shipin' | 'shezhi' | 'jianzhi' | 'jiaotong' | 'tongxun' | 'gouwu' | 'canyin' | 'zhufang' | 'weixiu' | 'fushi' | 'riyongpin' | 'kuaidi' | 'qita' | 'ruanjian' | 'yule' | 'weixin' | 'zhiwen' | 'QQ'; interface Props extends GProps, ViewProps { name: IconNames; @@ -37,28 +57,48 @@ interface Props extends GProps, ViewProps { let IconFont: FunctionComponent = ({ name, ...rest }) => { switch (name) { - case 'zhichu': - return ; - case 'shouru': - return ; case 'gongzi': - return ; - case 'jiaotong': - return ; - case 'shucai': - return ; - case 'riyongpin': - return ; - case 'yule': - return ; + return ; + case 'lijin': + return ; case 'lingshi': - return ; + return ; + case 'shipin': + return ; + case 'shezhi': + return ; + case 'jianzhi': + return ; + case 'jiaotong': + return ; + case 'tongxun': + return ; + case 'gouwu': + return ; + case 'canyin': + return ; + case 'zhufang': + return ; + case 'weixiu': + return ; + case 'fushi': + return ; + case 'riyongpin': + return ; + case 'kuaidi': + return ; + case 'qita': + return ; + case 'ruanjian': + return ; + case 'yule': + return ; case 'weixin': - return ; + return ; case 'zhiwen': - return ; + return ; case 'QQ': - return ; + return ; } return null; diff --git a/code/base-project/base-app/src/request/api/money.ts b/code/base-project/base-app/src/request/api/money.ts deleted file mode 100644 index c7764b82..00000000 --- a/code/base-project/base-app/src/request/api/money.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { MoneyCategory, MoneyRecord } from '@/types/money' -import alovaInstance from '../index' - -const API_PREFIX = '/money' - -export interface QueryMoneyRecordsParams { - record_time: string -} - -export interface QueryMoneyRecordsResult { - [key: string]: MoneyRecord[] -} -export function queryMoneyRecordsApi(params: QueryMoneyRecordsParams) { - return alovaInstance.Post>(`${API_PREFIX}/query`, params) -} - -export interface MoneyCategoryResult { - income: MoneyCategory[] - expense: MoneyCategory[] -} - -export function getMoneyCategoryApi() { - return alovaInstance.Get>(`${API_PREFIX}/category`) -} - -interface InsertMoneyRecordParams { - category_id: number - amount: string - record_time: string - remark: string -} - -export function insertMoneyRecordApi(params: InsertMoneyRecordParams) { - return alovaInstance.Post>(`${API_PREFIX}/insert`, params) -} - -interface UpdateMoneyRecordParams { - id: number - category_id: number - amount: string - record_time: string - remark: string -} - -export function updateMoneyRecordApi(params: UpdateMoneyRecordParams) { - return alovaInstance.Post>(`${API_PREFIX}/update`, params) -} - -interface DeleteMoneyRecordParams { - id: number -} - -export function deleteMoneyRecordApi(params: DeleteMoneyRecordParams) { - return alovaInstance.Post>(`${API_PREFIX}/delete`, params) -} diff --git a/code/base-project/base-app/src/request/api/money/category.ts b/code/base-project/base-app/src/request/api/money/category.ts new file mode 100644 index 00000000..96288d34 --- /dev/null +++ b/code/base-project/base-app/src/request/api/money/category.ts @@ -0,0 +1,8 @@ +import type { QueryMoneyCategoryResult } from '@/types/money/category' +import alovaInstance from '../../index' + +const API_PREFIX = '/money' + +export function queryMoneyCategoryApi() { + return alovaInstance.Get>(`${API_PREFIX}/category`) +} diff --git a/code/base-project/base-app/src/request/api/money/record.ts b/code/base-project/base-app/src/request/api/money/record.ts new file mode 100644 index 00000000..aad944cf --- /dev/null +++ b/code/base-project/base-app/src/request/api/money/record.ts @@ -0,0 +1,12 @@ +import type { InsertMoneyRecordParams, InsertMoneyRecordResult, QueryMoneyRecordsParams, QueryMoneyRecordsResult } from '@/types/money/record' +import alovaInstance from '../../index' + +const API_PREFIX = '/money' + +export function queryMoneyRecordsApi(params: QueryMoneyRecordsParams) { + return alovaInstance.Post>(`${API_PREFIX}/query`, params) +} + +export function insertMoneyRecordApi(params: InsertMoneyRecordParams) { + return alovaInstance.Post>(`${API_PREFIX}/insert`, params) +} diff --git a/code/base-project/base-app/src/request/index.ts b/code/base-project/base-app/src/request/index.ts index 6c068bd8..4085918d 100644 --- a/code/base-project/base-app/src/request/index.ts +++ b/code/base-project/base-app/src/request/index.ts @@ -30,8 +30,8 @@ function isWhiteListed(url: string) { } const alovaInstance = createAlova({ - // baseURL: 'http://192.168.5.6:8085/app', - baseURL: 'http://192.168.1.136:8085/app', + baseURL: 'http://192.168.5.6:8085/app', + // baseURL: 'http://192.168.1.136:8085/app', requestAdapter: axiosRequestAdapter(), timeout: 5000, cacheFor: null, diff --git a/code/base-project/base-app/src/static/images/Empty.svg b/code/base-project/base-app/src/static/images/Empty.svg new file mode 100644 index 00000000..90fb7ef7 --- /dev/null +++ b/code/base-project/base-app/src/static/images/Empty.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/code/base-project/base-app/src/static/images/Error.svg b/code/base-project/base-app/src/static/images/Error.svg new file mode 100644 index 00000000..37e2934f --- /dev/null +++ b/code/base-project/base-app/src/static/images/Error.svg @@ -0,0 +1 @@ +server down \ No newline at end of file diff --git a/code/base-project/base-app/src/static/images/NotFound.svg b/code/base-project/base-app/src/static/images/NotFound.svg new file mode 100644 index 00000000..d79b7a22 --- /dev/null +++ b/code/base-project/base-app/src/static/images/NotFound.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/code/base-project/base-app/src/types/declarations.d.ts b/code/base-project/base-app/src/types/declarations.d.ts new file mode 100644 index 00000000..bcbd6e2b --- /dev/null +++ b/code/base-project/base-app/src/types/declarations.d.ts @@ -0,0 +1,7 @@ +declare module '*.svg' { + import type React from 'react' + import type { SvgProps } from 'react-native-svg' + + const content: React.FC + export default content +} diff --git a/code/base-project/base-app/src/types/money.ts b/code/base-project/base-app/src/types/money.ts deleted file mode 100644 index 0d300300..00000000 --- a/code/base-project/base-app/src/types/money.ts +++ /dev/null @@ -1,18 +0,0 @@ -export interface MoneyCategory { - id: number - user_id: number - name: string - icon: string - sort_number: number - type: number -} - -export interface MoneyRecord { - id: number - category_id: number - user_id: number - amount: string - remark: string - record_time: string - create_time: string -} diff --git a/code/base-project/base-app/src/types/money/category.ts b/code/base-project/base-app/src/types/money/category.ts new file mode 100644 index 00000000..de80bbd3 --- /dev/null +++ b/code/base-project/base-app/src/types/money/category.ts @@ -0,0 +1,18 @@ +export interface MoneyCategoryBase { + id: number + user_id: number + name: string + icon: string + sort_number: number + type: number +} + +// 查询 +export interface MoneyCategoryItem extends MoneyCategoryBase { + +} + +export interface QueryMoneyCategoryResult { + income: MoneyCategoryItem[] + expense: MoneyCategoryItem[] +} diff --git a/code/base-project/base-app/src/types/money/record.ts b/code/base-project/base-app/src/types/money/record.ts new file mode 100644 index 00000000..5b2a3162 --- /dev/null +++ b/code/base-project/base-app/src/types/money/record.ts @@ -0,0 +1,45 @@ +// types/money/record.ts + +// 基础记录 +export interface MoneyRecordBase { + id: number + category_id: number + user_id: number + amount: string + remark: string + record_time: string + create_time: string +} + +// 查询条件(请求参数) +export interface QueryMoneyRecordsParams { + record_time: string +} + +// 查询结果的记录 +export interface MoneyRecordItem extends MoneyRecordBase { + category_name: string + category_icon: string + category_type: number +} + +// 分组 & 查询结果 + +export interface MoneyRecordGroup { + record_time: string + expense: string + income: string + records: MoneyRecordItem[] +} + +export interface QueryMoneyRecordsResult { + records: MoneyRecordGroup[] + total_income: string + total_expense: string +} + +// 新增请求参数 +export type InsertMoneyRecordParams = Omit + +// 新增返回结果 +export interface InsertMoneyRecordResult extends MoneyRecordBase {} diff --git a/code/base-project/base-app/src/utils/time.ts b/code/base-project/base-app/src/utils/time.ts index b76d0dae..a7949e04 100644 --- a/code/base-project/base-app/src/utils/time.ts +++ b/code/base-project/base-app/src/utils/time.ts @@ -27,3 +27,38 @@ export function getCurrentTime(format = 'HH:mm:ss'): string { export function getCurrentYearMonth(format = 'YYYY-MM'): string { return dayjs().format(format) } + +/** 字符串 / 数字 / Date → Date(无效返回 null) */ +export function toDate(input: string | number | Date | undefined | null): Date { + if (!input) + return new Date() + if (input instanceof Date) + return input + + const d = dayjs(input) + return d.isValid() ? d.toDate() : new Date() +} + +/** Date → YYYY-MM-DD */ +export function toDateString(date: string | number | Date): string { + const d = dayjs(toDate(date)) + return d.isValid() ? d.format('YYYY-MM-DD') : '' +} + +/** Date → YYYY-MM */ +export function toYearMonthString(date: string | number | Date): string { + const d = dayjs(toDate(date)) + return d.isValid() ? d.format('YYYY-MM') : '' +} + +/** Date → HH:mm:ss */ +export function toTimeString(date: string | number | Date): string { + const d = dayjs(toDate(date)) + return d.isValid() ? d.format('HH:mm:ss') : '' +} + +/** Date → YYYY-MM-DD HH:mm:ss */ +export function toDateTimeString(date: string | number | Date): string { + const d = dayjs(toDate(date)) + return d.isValid() ? d.format('YYYY-MM-DD HH:mm:ss') : '' +} diff --git a/code/base-project/base-go-v2/internal/api/money/index.go b/code/base-project/base-go-v2/internal/api/money/index.go index 7d22f070..eb736a8e 100644 --- a/code/base-project/base-go-v2/internal/api/money/index.go +++ b/code/base-project/base-go-v2/internal/api/money/index.go @@ -7,8 +7,10 @@ import ( "base-go-v2/internal/utils/idgen" "base-go-v2/internal/utils/mapx" "fmt" - "github.com/shopspring/decimal" + "sort" "time" + + "github.com/shopspring/decimal" ) func InitMoneyRouter(r *router.Router) { @@ -54,7 +56,6 @@ func InitDefaultCategories(userID int64) error { return nil } -// 根据 func queryMoneyRecords(c *router.Context) error { bodyData, err := c.GetBodyWithRequired("record_time") // "YYYY-MM" if err != nil { @@ -72,38 +73,37 @@ func queryMoneyRecords(c *router.Context) error { // 获取当月最后一天 endTime := startTime.AddDate(0, 1, 0).Add(-time.Nanosecond) - // SQL: money_record LEFT JOIN money_user_category + // 查询 SQL sqlStr := fmt.Sprintf(` - SELECT - mr.*, - muc.name AS category_name, - muc.icon AS category_icon, - muc.type AS category_type - FROM money_record mr - LEFT JOIN money_user_category muc ON mr.category_id = muc.id - WHERE mr.create_time BETWEEN '%s' AND '%s' - ORDER BY mr.create_time DESC - `, startTime.Format("2006-01-02 15:04:05"), endTime.Format("2006-01-02 15:04:05")) + SELECT + mr.*, + muc.name AS category_name, + muc.icon AS category_icon, + muc.type AS category_type + FROM money_record mr + LEFT JOIN money_user_category muc ON mr.category_id = muc.id + WHERE mr.create_time BETWEEN '%s' AND '%s' + ORDER BY mr.record_time DESC, mr.create_time DESC + `, startTime.Format("2006-01-02 15:04:05"), endTime.Format("2006-01-02 15:04:05")) - // 查询 list, err := db.SelectBySql(sqlStr) if err != nil { return c.AddError(err) } // 分组数据 - grouped := mapx.New() // mapx.M + grouped := mapx.New() totalIncome := decimal.NewFromInt(0) totalExpense := decimal.NewFromInt(0) for _, r := range list { row := mapx.M(r) - createTime, ok := row["create_time"].(time.Time) + recordTime, ok := row["record_time"].(time.Time) if !ok { continue } - day := createTime.Format("2006-01-02") + day := recordTime.Format("2006-01-02") // 获取当天数据 dayDataI := grouped.Get(day) @@ -129,15 +129,8 @@ func queryMoneyRecords(c *router.Context) error { continue } - dayIncome, err := decimal.NewFromString(dayData.GetString("income")) - if err != nil { - dayIncome = decimal.NewFromInt(0) - } - - dayExpense, err := decimal.NewFromString(dayData.GetString("expense")) - if err != nil { - dayExpense = decimal.NewFromInt(0) - } + dayIncome, _ := decimal.NewFromString(dayData.GetString("income")) + dayExpense, _ := decimal.NewFromString(dayData.GetString("expense")) if categoryType == 0 { dayIncome = dayIncome.Add(amount) @@ -153,8 +146,28 @@ func queryMoneyRecords(c *router.Context) error { grouped.Set(day, dayData) } + // 对日期排序,最新在前 + dates := make([]string, 0, len(grouped)) + for k := range grouped { + dates = append(dates, k) + } + sort.Slice(dates, func(i, j int) bool { + return dates[i] > dates[j] // 倒序 + }) + + // 构建最终 records 数组 + recordsArr := make([]mapx.M, 0, len(dates)) + for _, date := range dates { + dayData := grouped.Get(date).(mapx.M) + recordsArr = append(recordsArr, mapx.New(). + Set("record_time", date). + Set("income", dayData.GetString("income")). + Set("expense", dayData.GetString("expense")). + Set("records", dayData.GetArray("records"))) + } + result := mapx.New(). - Set("records", grouped). + Set("records", recordsArr). Set("total_income", totalIncome.String()). Set("total_expense", totalExpense.String()) @@ -164,26 +177,27 @@ func queryMoneyRecords(c *router.Context) error { func getUserCategory(c *router.Context) error { userId := c.GetUserID() - // 查询当前用户的分类 - userCategories, err := db.SelectList("money_user_category", + // 查询当前用户的分类,已经按 sort_number 升序 + userCategories, err := db.SelectList( + "money_user_category", db.BuildWhereString(mapx.New().Set("user_id", userId)), - "sort_number ASC") - + "sort_number ASC", + ) if err != nil { return c.AddError(err) } - // 按 type 分组 + // 按 type 分组并保持顺序 result := map[string][]mapx.M{ "income": {}, "expense": {}, } for _, cat := range userCategories { - switch cat.GetInt("type") { - case 0: + t := cat.GetInt("type") + if t == 0 { result["income"] = append(result["income"], cat) - case 1: + } else if t == 1 { result["expense"] = append(result["expense"], cat) } } diff --git a/empty.svg b/empty.svg new file mode 100644 index 00000000..90fb7ef7 --- /dev/null +++ b/empty.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/error.svg b/error.svg new file mode 100644 index 00000000..37e2934f --- /dev/null +++ b/error.svg @@ -0,0 +1 @@ +server down \ No newline at end of file