diff --git a/code/base-project/base-app/package.json b/code/base-project/base-app/package.json index bf332bab..392ea86b 100644 --- a/code/base-project/base-app/package.json +++ b/code/base-project/base-app/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@alova/adapter-axios": "^2.0.16", + "@expo/html-elements": "0.12.5", "@gluestack-ui/core": "^3.0.12", "@gluestack-ui/utils": "^3.0.11", "@gluestack/ui-next-adapter": "^3.0.3", @@ -44,6 +45,7 @@ "react-native-modal": "14.0.0-rc.1", "react-native-pager-view": "6.9.1", "react-native-popup-menu": "^0.18.0", + "react-native-qrcode-svg": "^6.3.20", "react-native-reanimated": "~4.1.3", "react-native-safe-area-context": "~5.6.1", "react-native-screens": "~4.16.0", diff --git a/code/base-project/base-app/pnpm-lock.yaml b/code/base-project/base-app/pnpm-lock.yaml index 5024eb16..3669508f 100644 --- a/code/base-project/base-app/pnpm-lock.yaml +++ b/code/base-project/base-app/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@alova/adapter-axios': specifier: ^2.0.16 version: 2.0.16(alova@3.3.4)(axios@1.13.2) + '@expo/html-elements': + specifier: 0.12.5 + version: 0.12.5 '@gluestack-ui/core': specifier: ^3.0.12 version: 3.0.12(@gluestack-ui/utils@3.0.12(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.18(yaml@2.8.1)))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) @@ -110,6 +113,9 @@ importers: react-native-popup-menu: specifier: ^0.18.0 version: 0.18.0 + react-native-qrcode-svg: + specifier: ^6.3.20 + version: 6.3.20(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) 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) @@ -875,6 +881,9 @@ packages: resolution: {integrity: sha512-8YPJpEYlmV171fi+t+cSLMX1nC5ngY9j2FiN70dHldLpd6Ct6ouGhk96svJ4BQZwsqwII2pokwzrDAwqo4Z0FQ==} hasBin: true + '@expo/html-elements@0.12.5': + resolution: {integrity: sha512-28KWO88YKykKU7ke5sEQs5TivFRMs1Aktz13xxgqAf5rTgb+lka0VKVt3W2fG7ksbUQ407rtUqz7SEAq298NvQ==} + '@expo/image-utils@0.8.7': resolution: {integrity: sha512-SXOww4Wq3RVXLyOaXiCCuQFguCDh8mmaHBv54h/R29wGl4jRY8GEyQEx8SypV/iHt1FbzsU/X3Qbcd9afm2W2w==} @@ -2631,6 +2640,9 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -2814,6 +2826,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} @@ -2884,6 +2900,9 @@ packages: resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -3911,56 +3930,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==} @@ -4665,6 +4676,10 @@ packages: resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} engines: {node: '>=4.0.0'} + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + pnpm-workspace-yaml@1.3.0: resolution: {integrity: sha512-Krb5q8Totd5mVuLx7we+EFHq/AfxA75nbfTm25Q1pIf606+RlaKUG+PXH8SDihfe5b5k4H09gE+sL47L1t5lbw==} @@ -4763,6 +4778,11 @@ packages: resolution: {integrity: sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==} hasBin: true + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + hasBin: true + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} @@ -4885,6 +4905,13 @@ packages: react-native-popup-menu@0.18.0: resolution: {integrity: sha512-XD3gyp/hwL5YWw2J034DerfvbJ6S2YHqAzvqAFRU+UGnFD4JyTqggfm4UyynBD26O1PDoRb45Loil+NZCGfCnA==} + react-native-qrcode-svg@6.3.20: + resolution: {integrity: sha512-GDP7T3DDEHUo53xmDyWWXXm3MhWRp0YayqVMum98JYfm0DW2rEbz1GIj+XLaA0QX443G0nURyzPnuQJeHjuvjA==} + peerDependencies: + react: '*' + react-native: '>=0.63.4' + react-native-svg: '>=14.0.0' + react-native-reanimated@4.1.5: resolution: {integrity: sha512-UA6VUbxwhRjEw2gSNrvhkusUq3upfD3Cv+AnB07V+kC8kpvwRVI+ivwY95ePbWNFkFpP+Y2Sdw1WHpHWEV+P2Q==} peerDependencies: @@ -5040,6 +5067,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + requireg@0.2.2: resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} engines: {node: '>= 4.0.0'} @@ -5148,6 +5178,9 @@ packages: server-only@0.0.1: resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -5375,6 +5408,10 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + text-encoding@0.7.0: + resolution: {integrity: sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==} + deprecated: no longer maintained + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -5609,6 +5646,9 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -5621,6 +5661,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -5695,6 +5739,9 @@ packages: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5715,10 +5762,18 @@ packages: engines: {node: '>= 14.6'} hasBin: true + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -6698,6 +6753,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@expo/html-elements@0.12.5': {} + '@expo/image-utils@0.8.7': dependencies: '@expo/spawn-async': 1.7.2 @@ -9139,6 +9196,12 @@ snapshots: client-only@0.0.1: {} + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -9310,6 +9373,8 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decimal.js@10.6.0: {} decode-named-character-reference@1.2.0: @@ -9358,6 +9423,8 @@ snapshots: diff-sequences@27.5.1: {} + dijkstrajs@1.0.3: {} + dlv@1.1.3: {} dom-helpers@6.0.1: @@ -11581,6 +11648,8 @@ snapshots: pngjs@3.4.0: {} + pngjs@5.0.0: {} + pnpm-workspace-yaml@1.3.0: dependencies: yaml: 2.8.1 @@ -11668,6 +11737,12 @@ snapshots: qrcode-terminal@0.11.0: {} + qrcode@1.5.4: + dependencies: + dijkstrajs: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + quansync@0.2.11: {} query-string@7.1.3: @@ -11841,6 +11916,15 @@ snapshots: react-native-popup-menu@0.18.0: {} + react-native-qrcode-svg@6.3.20(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + dependencies: + prop-types: 15.8.1 + qrcode: 1.5.4 + react: 19.1.0 + react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0) + react-native-svg: 15.12.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + text-encoding: 0.7.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: '@babel/core': 7.28.5 @@ -12080,6 +12164,8 @@ snapshots: require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} + requireg@0.2.2: dependencies: nested-error-stacks: 2.0.1 @@ -12198,6 +12284,8 @@ snapshots: server-only@0.0.1: {} + set-blocking@2.0.0: {} + setimmediate@1.0.5: {} setprototypeof@1.2.0: {} @@ -12427,6 +12515,8 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 + text-encoding@0.7.0: {} + thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -12629,6 +12719,8 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 + which-module@2.0.1: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -12637,6 +12729,12 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -12685,6 +12783,8 @@ snapshots: xmlbuilder@15.1.1: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -12698,8 +12798,27 @@ snapshots: yaml@2.8.1: {} + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + yargs-parser@21.1.1: {} + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yargs@17.7.2: dependencies: cliui: 8.0.1 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 b219f555..0c02eea5 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,6 +1,6 @@ import type { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record' import React, { useCallback, useState } from 'react' -import { RefreshControl, SectionList, Text, TouchableHighlight, View } from 'react-native' +import { RefreshControl, SectionList, Text, TouchableHighlight, Vibration, View } from 'react-native' import { Menu, MenuOption, @@ -120,7 +120,6 @@ export default function StaticTransactions({ renderItem={({ item, index }) => { const category = moneyCategoryStore.getCategoryById(item.category_id) - return ( setSelectedId(item.id)} onClose={() => setSelectedId(null)} > - + { + Vibration.vibrate(50) + }} + > - (null) @@ -14,9 +36,11 @@ export default function PagerWithTab() { code: '', }) + const [accordion, setAccordion] = useState(['a']) + function EnterSapce() { return ( - + - 加入空间 + 加入空间 - + 或 - + - 扫码加入 + 扫码加入 + + 返回 + ) } + const members = [ + { id: 1, name: '张三' }, + { id: 2, name: '李四' }, + { id: 3, name: '王五' }, + ] return ( @@ -79,24 +111,65 @@ export default function PagerWithTab() { 加入已有空间 */} - - - - 邀请好友加入 - - - + { + setAccordion(value) + }} + > + + + + {({ isExpanded }: { isExpanded: boolean }) => { + return ( + <> + + 我的邀请码 + + {isExpanded + ? ( + + ) + : ( + + )} + + ) + }} + + + - 123456 - 复制代码 - - + > + + 123456 + + - + + + + + + + + 空间成员 @@ -104,12 +177,65 @@ export default function PagerWithTab() { - - 列表 + + item.id.toString()} + renderItem={({ item }) => ( + + + + + {item.name} + + + + + + {item.name} + + 管理员 + + + Marketing Coordinator + + + + ( + + + + )} + > + + 添加为管理员 + + + 移出空间 + + + + + + )} + /> + 退出该空间 - + */} + + ) diff --git a/code/base-project/base-app/src/components/common/ao/Divider.tsx b/code/base-project/base-app/src/components/common/ao/Divider.tsx new file mode 100644 index 00000000..252dc37c --- /dev/null +++ b/code/base-project/base-app/src/components/common/ao/Divider.tsx @@ -0,0 +1,74 @@ +import type { ViewStyle } from 'react-native' +import React from 'react' +import { Text, View } from 'react-native' + +interface DividerProps { + direction?: 'horizontal' | 'vertical' + text?: string | React.ReactNode + textPosition?: 'left' | 'center' | 'right' + style?: ViewStyle + className?: string +} + +export default function Divider({ + direction = 'horizontal', + text, + textPosition = 'center', + style, + className, +}: DividerProps) { + const isString = typeof text === 'string' + + // 垂直分割线 + if (direction === 'vertical') { + return ( + + ) + } + + // 水平,无文字 + if (!text) { + return ( + + ) + } + + // 水平 + 文本 + return ( + + {/* 左线 */} + + + {/* 文本(字符串 → 自动包裹 Text;node → 直接渲染) */} + + {isString + ? ( + {text} + ) + : ( + text + )} + + + {/* 右线 */} + + + ) +} 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 289dbc1c..6939a3b0 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 @@ -2,6 +2,7 @@ import Button from './Button' import { Cell, CellGroup } from './Cell' import Checkbox from './Checkbox' import DatePicker from './DatePicker' +import Divider from './Divider' import Form, { FormRef } from './Form' import FormItem from './FormItem' import Input from './Input' @@ -16,6 +17,7 @@ export { CellGroup as ACellGroup, Checkbox as ACheckbox, DatePicker as ADatePicker, + Divider as ADivider, Form as AForm, FormItem as AFormItem, FormRef as AFormRef, diff --git a/code/base-project/base-app/src/components/ui/accordion/index.tsx b/code/base-project/base-app/src/components/ui/accordion/index.tsx new file mode 100644 index 00000000..f32d010e --- /dev/null +++ b/code/base-project/base-app/src/components/ui/accordion/index.tsx @@ -0,0 +1,331 @@ +'use client'; +import React from 'react'; +import { createAccordion } from '@gluestack-ui/core/accordion/creator'; +import { View, Pressable, Text, Platform, TextProps } from 'react-native'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { + withStyleContext, + useStyleContext, +} from '@gluestack-ui/utils/nativewind-utils'; +import { H3 } from '@expo/html-elements'; +import { cssInterop } from 'nativewind'; +import { PrimitiveIcon, UIIcon } from '@gluestack-ui/core/icon/creator'; + +const SCOPE = 'ACCORDION'; +/** Styles */ + +const accordionStyle = tva({ + base: 'w-full', + variants: { + variant: { + filled: 'bg-white shadow-hard-2', + unfilled: '', + }, + size: { + sm: '', + md: '', + lg: '', + }, + }, +}); + +const accordionItemStyle = tva({ + base: '', + parentVariants: { + variant: { + filled: 'bg-background-0', + unfilled: 'bg-transparent', + }, + }, +}); +const accordionTitleTextStyle = tva({ + base: 'text-typography-900 font-bold flex-1 text-left', + parentVariants: { + size: { + sm: 'text-sm', + md: 'text-base', + lg: 'text-lg', + }, + }, +}); +const accordionIconStyle = tva({ + base: 'text-typography-900 fill-none', + parentVariants: { + size: { + '2xs': 'h-3 w-3', + 'xs': 'h-3.5 w-3.5', + 'sm': 'h-4 w-4', + 'md': 'h-[18px] w-[18px]', + 'lg': 'h-5 w-5', + 'xl': 'h-6 w-6', + }, + }, +}); +const accordionContentTextStyle = tva({ + base: 'text-typography-700 font-normal', + parentVariants: { + size: { + sm: 'text-sm', + md: 'text-base', + lg: 'text-lg', + }, + }, +}); +const accordionHeaderStyle = tva({ + base: 'mx-0 my-0', +}); +const accordionContentStyle = tva({ + base: 'pt-1 pb-3 px-4', +}); +const accordionTriggerStyle = tva({ + base: 'w-full flex-row justify-between items-center web:outline-none focus:outline-none data-[disabled=true]:opacity-40 data-[disabled=true]:cursor-not-allowed data-[focus-visible=true]:bg-background-50 py-3 px-4', +}); + +const Root = withStyleContext(View, SCOPE); + +const Header = ( + Platform.OS === 'web' ? H3 : View +) as React.ComponentType; + +/** Creator */ +const UIAccordion = createAccordion({ + Root: Root, + Item: View, + Header: Header, + Trigger: Pressable, + Icon: UIIcon, + TitleText: Text, + ContentText: Text, + Content: View, +}); + +cssInterop(PrimitiveIcon, { + className: { + target: 'style', + nativeStyleToProp: { + height: true, + width: true, + fill: true, + color: 'classNameColor', + stroke: true, + }, + }, +}); + +cssInterop(H3, { + className: { + target: 'style', + }, +}); + +type IAccordionProps = React.ComponentPropsWithoutRef & + VariantProps; + +type IAccordionItemProps = React.ComponentPropsWithoutRef< + typeof UIAccordion.Item +> & + VariantProps; + +type IAccordionContentProps = React.ComponentPropsWithoutRef< + typeof UIAccordion.Content +> & + VariantProps; + +type IAccordionContentTextProps = React.ComponentPropsWithoutRef< + typeof UIAccordion.ContentText +> & + VariantProps; + +type IAccordionIconProps = VariantProps & + React.ComponentPropsWithoutRef & { + as?: React.ElementType; + height?: number; + width?: number; + }; + +type IAccordionHeaderProps = React.ComponentPropsWithoutRef< + typeof UIAccordion.Header +> & + VariantProps; + +type IAccordionTriggerProps = React.ComponentPropsWithoutRef< + typeof UIAccordion.Trigger +> & + VariantProps; + +type IAccordionTitleTextProps = React.ComponentPropsWithoutRef< + typeof UIAccordion.TitleText +> & + VariantProps; + +/** Components */ + +const Accordion = React.forwardRef< + React.ComponentRef, + IAccordionProps +>(({ className, variant = 'filled', size = 'md', ...props }, ref) => { + return ( + + ); +}); + +const AccordionItem = React.forwardRef< + React.ComponentRef, + IAccordionItemProps +>(({ className, ...props }, ref) => { + const { variant } = useStyleContext(SCOPE); + return ( + + ); +}); + +const AccordionContent = React.forwardRef< + React.ComponentRef, + IAccordionContentProps +>(function AccordionContent({ className, ...props }, ref) { + return ( + + ); +}); + +const AccordionContentText = React.forwardRef< + React.ComponentRef, + IAccordionContentTextProps +>(function AccordionContentText({ className, ...props }, ref) { + const { size } = useStyleContext(SCOPE); + return ( + + ); +}); + +const AccordionIcon = React.forwardRef< + React.ComponentRef, + IAccordionIconProps +>(function AccordionIcon({ size, className, ...props }, ref) { + const { size: parentSize } = useStyleContext(SCOPE); + + if (typeof size === 'number') { + return ( + + ); + } else if ( + (props.height !== undefined || props.width !== undefined) && + size === undefined + ) { + return ( + + ); + } + return ( + + ); +}); + +const AccordionHeader = React.forwardRef< + React.ComponentRef, + IAccordionHeaderProps +>(function AccordionHeader({ className, ...props }, ref) { + return ( + + ); +}); + +const AccordionTrigger = React.forwardRef< + React.ComponentRef, + IAccordionTriggerProps +>(function AccordionTrigger({ className, ...props }, ref) { + return ( + + ); +}); +const AccordionTitleText = React.forwardRef< + React.ComponentRef, + IAccordionTitleTextProps +>(function AccordionTitleText({ className, ...props }, ref) { + const { size } = useStyleContext(SCOPE); + return ( + + ); +}); + +Accordion.displayName = 'Accordion'; +AccordionItem.displayName = 'AccordionItem'; +AccordionHeader.displayName = 'AccordionHeader'; +AccordionTrigger.displayName = 'AccordionTrigger'; +AccordionTitleText.displayName = 'AccordionTitleText'; +AccordionContentText.displayName = 'AccordionContentText'; +AccordionIcon.displayName = 'AccordionIcon'; +AccordionContent.displayName = 'AccordionContent'; + +export { + Accordion, + AccordionItem, + AccordionHeader, + AccordionTrigger, + AccordionTitleText, + AccordionContentText, + AccordionIcon, + AccordionContent, +}; diff --git a/code/base-project/base-app/src/components/ui/heading/index.tsx b/code/base-project/base-app/src/components/ui/heading/index.tsx new file mode 100644 index 00000000..143cb4be --- /dev/null +++ b/code/base-project/base-app/src/components/ui/heading/index.tsx @@ -0,0 +1,220 @@ +import React, { forwardRef, memo } from 'react'; +import { H1, H2, H3, H4, H5, H6 } from '@expo/html-elements'; +import { headingStyle } from './styles'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { cssInterop } from 'nativewind'; + +type IHeadingProps = VariantProps & + React.ComponentPropsWithoutRef & { + as?: React.ElementType; + }; + +cssInterop(H1, { className: 'style' }); +cssInterop(H2, { className: 'style' }); +cssInterop(H3, { className: 'style' }); +cssInterop(H4, { className: 'style' }); +cssInterop(H5, { className: 'style' }); +cssInterop(H6, { className: 'style' }); + +const MappedHeading = memo( + forwardRef, IHeadingProps>( + function MappedHeading( + { + size, + className, + isTruncated, + bold, + underline, + strikeThrough, + sub, + italic, + highlight, + ...props + }, + ref + ) { + switch (size) { + case '5xl': + case '4xl': + case '3xl': + return ( +

+ ); + case '2xl': + return ( +

+ ); + case 'xl': + return ( +

+ ); + case 'lg': + return ( +

+ ); + case 'md': + return ( +

+ ); + case 'sm': + case 'xs': + return ( +
+ ); + default: + return ( +

+ ); + } + } + ) +); + +const Heading = memo( + forwardRef, IHeadingProps>(function Heading( + { className, size = 'lg', as: AsComp, ...props }, + ref + ) { + const { + isTruncated, + bold, + underline, + strikeThrough, + sub, + italic, + highlight, + } = props; + + if (AsComp) { + return ( + + ); + } + + return ( + + ); + }) +); + +Heading.displayName = 'Heading'; + +export { Heading }; diff --git a/code/base-project/base-app/src/components/ui/heading/index.web.tsx b/code/base-project/base-app/src/components/ui/heading/index.web.tsx new file mode 100644 index 00000000..92937f5f --- /dev/null +++ b/code/base-project/base-app/src/components/ui/heading/index.web.tsx @@ -0,0 +1,202 @@ +import React, { forwardRef, memo } from 'react'; +import { headingStyle } from './styles'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +type IHeadingProps = VariantProps & + React.ComponentPropsWithoutRef<'h1'> & { + as?: React.ElementType; + }; + +const MappedHeading = memo( + forwardRef(function MappedHeading( + { + size, + className, + isTruncated, + bold, + underline, + strikeThrough, + sub, + italic, + highlight, + ...props + }, + ref + ) { + switch (size) { + case '5xl': + case '4xl': + case '3xl': + return ( +

+ ); + case '2xl': + return ( +

+ ); + case 'xl': + return ( +

+ ); + case 'lg': + return ( +

+ ); + case 'md': + return ( +

+ ); + case 'sm': + case 'xs': + return ( +
+ ); + default: + return ( +

+ ); + } + }) +); + +const Heading = memo( + forwardRef(function Heading( + { className, size = 'lg', as: AsComp, ...props }, + ref + ) { + const { + isTruncated, + bold, + underline, + strikeThrough, + sub, + italic, + highlight, + } = props; + + if (AsComp) { + return ( + + ); + } + + return ( + + ); + }) +); + +Heading.displayName = 'Heading'; + +export { Heading }; diff --git a/code/base-project/base-app/src/components/ui/heading/styles.tsx b/code/base-project/base-app/src/components/ui/heading/styles.tsx new file mode 100644 index 00000000..fc896a38 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/heading/styles.tsx @@ -0,0 +1,43 @@ +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { isWeb } from '@gluestack-ui/utils/nativewind-utils'; +const baseStyle = isWeb + ? 'font-sans tracking-sm bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word' + : ''; + +export const headingStyle = tva({ + base: `text-typography-900 font-bold font-heading tracking-sm my-0 ${baseStyle}`, + variants: { + isTruncated: { + true: 'truncate', + }, + bold: { + true: 'font-bold', + }, + underline: { + true: 'underline', + }, + strikeThrough: { + true: 'line-through', + }, + sub: { + true: 'text-xs', + }, + italic: { + true: 'italic', + }, + highlight: { + true: 'bg-yellow-500', + }, + size: { + '5xl': 'text-6xl', + '4xl': 'text-5xl', + '3xl': 'text-4xl', + '2xl': 'text-3xl', + 'xl': 'text-2xl', + 'lg': 'text-xl', + 'md': 'text-lg', + 'sm': 'text-base', + 'xs': 'text-sm', + }, + }, +}); diff --git a/code/base-project/base-app/src/components/ui/hstack/index.tsx b/code/base-project/base-app/src/components/ui/hstack/index.tsx new file mode 100644 index 00000000..d05dc1b6 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/hstack/index.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { View } from 'react-native'; +import type { ViewProps } from 'react-native'; +import { hstackStyle } from './styles'; + +type IHStackProps = ViewProps & VariantProps; + +const HStack = React.forwardRef, IHStackProps>( + function HStack({ className, space, reversed, ...props }, ref) { + return ( + + ); + } +); + +HStack.displayName = 'HStack'; + +export { HStack }; diff --git a/code/base-project/base-app/src/components/ui/hstack/index.web.tsx b/code/base-project/base-app/src/components/ui/hstack/index.web.tsx new file mode 100644 index 00000000..58f5b6a9 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/hstack/index.web.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { hstackStyle } from './styles'; + +type IHStackProps = React.ComponentPropsWithoutRef<'div'> & + VariantProps; + +const HStack = React.forwardRef, IHStackProps>( + function HStack({ className, space, reversed, ...props }, ref) { + return ( +
+ ); + } +); + +HStack.displayName = 'HStack'; + +export { HStack }; diff --git a/code/base-project/base-app/src/components/ui/hstack/styles.tsx b/code/base-project/base-app/src/components/ui/hstack/styles.tsx new file mode 100644 index 00000000..2ab1e49f --- /dev/null +++ b/code/base-project/base-app/src/components/ui/hstack/styles.tsx @@ -0,0 +1,25 @@ +import { isWeb } from '@gluestack-ui/utils/nativewind-utils'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; + +const baseStyle = isWeb + ? 'flex relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none' + : ''; + +export const hstackStyle = tva({ + base: `flex-row ${baseStyle}`, + variants: { + space: { + 'xs': 'gap-1', + 'sm': 'gap-2', + 'md': 'gap-3', + 'lg': 'gap-4', + 'xl': 'gap-5', + '2xl': 'gap-6', + '3xl': 'gap-7', + '4xl': 'gap-8', + }, + reversed: { + true: 'flex-row-reverse', + }, + }, +}); diff --git a/code/base-project/base-app/src/components/ui/text/index.tsx b/code/base-project/base-app/src/components/ui/text/index.tsx new file mode 100644 index 00000000..868c53ed --- /dev/null +++ b/code/base-project/base-app/src/components/ui/text/index.tsx @@ -0,0 +1,48 @@ +import React from 'react'; + +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { Text as RNText } from 'react-native'; +import { textStyle } from './styles'; + +type ITextProps = React.ComponentProps & + VariantProps; + +const Text = React.forwardRef, ITextProps>( + function Text( + { + className, + isTruncated, + bold, + underline, + strikeThrough, + size = 'md', + sub, + italic, + highlight, + ...props + }, + ref + ) { + return ( + + ); + } +); + +Text.displayName = 'Text'; + +export { Text }; diff --git a/code/base-project/base-app/src/components/ui/text/index.web.tsx b/code/base-project/base-app/src/components/ui/text/index.web.tsx new file mode 100644 index 00000000..7ccf97ea --- /dev/null +++ b/code/base-project/base-app/src/components/ui/text/index.web.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { textStyle } from './styles'; + +type ITextProps = React.ComponentProps<'span'> & VariantProps; + +const Text = React.forwardRef, ITextProps>( + function Text( + { + className, + isTruncated, + bold, + underline, + strikeThrough, + size = 'md', + sub, + italic, + highlight, + ...props + }: { className?: string } & ITextProps, + ref + ) { + return ( + + ); + } +); + +Text.displayName = 'Text'; + +export { Text }; diff --git a/code/base-project/base-app/src/components/ui/text/styles.tsx b/code/base-project/base-app/src/components/ui/text/styles.tsx new file mode 100644 index 00000000..bf2c50aa --- /dev/null +++ b/code/base-project/base-app/src/components/ui/text/styles.tsx @@ -0,0 +1,47 @@ +import { tva } from '@gluestack-ui/utils/nativewind-utils'; +import { isWeb } from '@gluestack-ui/utils/nativewind-utils'; + +const baseStyle = isWeb + ? 'font-sans tracking-sm my-0 bg-transparent border-0 box-border display-inline list-none margin-0 padding-0 position-relative text-start no-underline whitespace-pre-wrap word-wrap-break-word' + : ''; + +export const textStyle = tva({ + base: `text-typography-700 font-body ${baseStyle}`, + + variants: { + isTruncated: { + true: 'web:truncate', + }, + bold: { + true: 'font-bold', + }, + underline: { + true: 'underline', + }, + strikeThrough: { + true: 'line-through', + }, + size: { + '2xs': 'text-2xs', + 'xs': 'text-xs', + 'sm': 'text-sm', + 'md': 'text-base', + 'lg': 'text-lg', + 'xl': 'text-xl', + '2xl': 'text-2xl', + '3xl': 'text-3xl', + '4xl': 'text-4xl', + '5xl': 'text-5xl', + '6xl': 'text-6xl', + }, + sub: { + true: 'text-xs', + }, + italic: { + true: 'italic', + }, + highlight: { + true: 'bg-yellow-500', + }, + }, +}); diff --git a/code/base-project/base-app/src/components/ui/vstack/index.tsx b/code/base-project/base-app/src/components/ui/vstack/index.tsx new file mode 100644 index 00000000..76e42103 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/vstack/index.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; +import { View } from 'react-native'; + +import { vstackStyle } from './styles'; + +type IVStackProps = React.ComponentProps & + VariantProps; + +const VStack = React.forwardRef, IVStackProps>( + function VStack({ className, space, reversed, ...props }, ref) { + return ( + + ); + } +); + +VStack.displayName = 'VStack'; + +export { VStack }; diff --git a/code/base-project/base-app/src/components/ui/vstack/index.web.tsx b/code/base-project/base-app/src/components/ui/vstack/index.web.tsx new file mode 100644 index 00000000..2389e1f3 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/vstack/index.web.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils'; + +import { vstackStyle } from './styles'; + +type IVStackProps = React.ComponentProps<'div'> & + VariantProps; + +const VStack = React.forwardRef, IVStackProps>( + function VStack({ className, space, reversed, ...props }, ref) { + return ( +
+ ); + } +); + +VStack.displayName = 'VStack'; + +export { VStack }; diff --git a/code/base-project/base-app/src/components/ui/vstack/styles.tsx b/code/base-project/base-app/src/components/ui/vstack/styles.tsx new file mode 100644 index 00000000..83a08cc9 --- /dev/null +++ b/code/base-project/base-app/src/components/ui/vstack/styles.tsx @@ -0,0 +1,25 @@ +import { isWeb } from '@gluestack-ui/utils/nativewind-utils'; +import { tva } from '@gluestack-ui/utils/nativewind-utils'; + +const baseStyle = isWeb + ? 'flex flex-col relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none' + : ''; + +export const vstackStyle = tva({ + base: `flex-col ${baseStyle}`, + variants: { + space: { + 'xs': 'gap-1', + 'sm': 'gap-2', + 'md': 'gap-3', + 'lg': 'gap-4', + 'xl': 'gap-5', + '2xl': 'gap-6', + '3xl': 'gap-7', + '4xl': 'gap-8', + }, + reversed: { + true: 'flex-col-reverse', + }, + }, +}); diff --git a/code/base-project/base-app/src/request/index.ts b/code/base-project/base-app/src/request/index.ts index 5cf7c043..7bf0ccca 100644 --- a/code/base-project/base-app/src/request/index.ts +++ b/code/base-project/base-app/src/request/index.ts @@ -32,8 +32,8 @@ function isWhiteListed(url: string) { } const alovaInstance = createAlova({ - // baseURL: 'http://192.168.5.6:8086/app', - baseURL: 'http://192.168.1.136:8086/app', + baseURL: 'http://192.168.5.6:8086/app', + // baseURL: 'http://192.168.1.136:8086/app', requestAdapter: axiosRequestAdapter(), timeout: 5000, cacheFor: null, diff --git a/code/base-project/base-app/test3.html b/code/base-project/base-app/test3.html index 0281671a..6039a47c 100644 --- a/code/base-project/base-app/test3.html +++ b/code/base-project/base-app/test3.html @@ -1,457 +1,148 @@ - + - - - 查询进度步骤条 - 精确对齐版本 - + .member-item:last-child { + border-bottom: none; + } + -
-
查询状态
-
- -
-
1
-
验证查询条件
-
- -
-
2
-
发出请求
-
+ +
邀请好友加入空间
- -
-
3
-
等待响应
-
+ +
- -
-
4
-
查询成功
-
- - -
-
-
- - -
-
-
- - -
-
-
-
- -
-
- 检查查询参数的有效性,确保数据请求符合系统要求。 -
已用时间: 0分00秒
-
-
+ +
+
+
我的邀请码
-