Compare commits

...

4 Commits
main ... v7

  1. 2
      .env
  2. 7
      package.json
  3. 211
      pnpm-lock.yaml
  4. BIN
      public/Alibaba-PuHuiTi-Heavy.ttf
  5. 3
      public/data.json
  6. 56
      src/App.tsx
  7. 15
      src/api/_utils/index.ts
  8. 57
      src/api/http.ts
  9. 17
      src/api/index.ts
  10. 17
      src/index.css
  11. 35
      src/layout/base.tsx
  12. 72
      src/plugins/http/base.ts
  13. 76
      src/plugins/http/index.ts
  14. 0
      src/plugins/http/plugins.ts
  15. 133
      src/plugins/http/plugins/Loading.ts
  16. 36
      src/plugins/http/plugins/Repeat.ts
  17. 34
      src/plugins/request.ts
  18. 16
      src/router-new/index.ts
  19. 54
      src/router/route.tsx
  20. 48
      src/store/account.ts
  21. 9
      src/ui/Login/Login.tsx
  22. 4
      src/ui/Register/Register.tsx
  23. 18
      src/views/About.tsx
  24. 9
      src/views/Child.tsx
  25. 47
      src/views/Home/index.tsx
  26. 11
      src/views/PlayGround.tsx
  27. 34
      src/views/Project.tsx
  28. 4
      src/viewsSys/NoMatch.tsx

2
.env

@ -1,2 +1,2 @@
# appwrite的项目ID # appwrite的项目ID
VUE_APPWRITE_PROJECT_ID= VITE_APP_WRITE_PROJECT_ID=

7
package.json

@ -17,7 +17,7 @@
"@blueprintjs/icons": "^5.14.0", "@blueprintjs/icons": "^5.14.0",
"@blueprintjs/table": "^5.2.5", "@blueprintjs/table": "^5.2.5",
"@types/lodash": "^4.17.13", "@types/lodash": "^4.17.13",
"@types/react-router-dom": "^5.3.3", "ahooks": "^3.8.2",
"appwrite": "^16.0.2", "appwrite": "^16.0.2",
"axios": "^1.7.7", "axios": "^1.7.7",
"framer-motion": "^11.11.17", "framer-motion": "^11.11.17",
@ -28,9 +28,10 @@
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "^7.53.2", "react-hook-form": "^7.53.2",
"react-markdown": "^9.0.1", "react-markdown": "^9.0.1",
"react-router-dom": "^5.3.4", "react-router": "^7.0.1",
"react-toastify": "^10.0.6", "react-toastify": "^10.0.6",
"styled-components": "^6.1.13" "styled-components": "^6.1.13",
"swr": "^2.2.5"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.13.0", "@eslint/js": "^9.13.0",

211
pnpm-lock.yaml

@ -23,9 +23,9 @@ importers:
'@types/lodash': '@types/lodash':
specifier: ^4.17.13 specifier: ^4.17.13
version: 4.17.13 version: 4.17.13
'@types/react-router-dom': ahooks:
specifier: ^5.3.3 specifier: ^3.8.2
version: 5.3.3 version: 3.8.2(react@18.3.1)
appwrite: appwrite:
specifier: ^16.0.2 specifier: ^16.0.2
version: 16.0.2 version: 16.0.2
@ -56,15 +56,18 @@ importers:
react-markdown: react-markdown:
specifier: ^9.0.1 specifier: ^9.0.1
version: 9.0.1(@types/react@18.3.12)(react@18.3.1) version: 9.0.1(@types/react@18.3.12)(react@18.3.1)
react-router-dom: react-router:
specifier: ^5.3.4 specifier: ^7.0.1
version: 5.3.4(react@18.3.1) version: 7.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react-toastify: react-toastify:
specifier: ^10.0.6 specifier: ^10.0.6
version: 10.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 10.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
styled-components: styled-components:
specifier: ^6 specifier: ^6
version: 6.1.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 6.1.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
swr:
specifier: ^2.2.5
version: 2.2.5(react@18.3.1)
devDependencies: devDependencies:
'@eslint/js': '@eslint/js':
specifier: ^9.13.0 specifier: ^9.13.0
@ -537,6 +540,9 @@ packages:
'@swc/types@0.1.15': '@swc/types@0.1.15':
resolution: {integrity: sha512-XKaZ+dzDIQ9Ot9o89oJQ/aluI17+VvUnIpYJTcZtvv1iYX6MzHh3Ik2CSR7MdPKpPwfZXHBeCingb2b4PoDVdw==} resolution: {integrity: sha512-XKaZ+dzDIQ9Ot9o89oJQ/aluI17+VvUnIpYJTcZtvv1iYX6MzHh3Ik2CSR7MdPKpPwfZXHBeCingb2b4PoDVdw==}
'@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
'@types/debug@4.1.12': '@types/debug@4.1.12':
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
@ -549,9 +555,6 @@ packages:
'@types/hast@3.0.4': '@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
'@types/history@4.7.11':
resolution: {integrity: sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==}
'@types/json-schema@7.0.15': '@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@ -573,12 +576,6 @@ packages:
'@types/react-dom@18.3.1': '@types/react-dom@18.3.1':
resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==} resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==}
'@types/react-router-dom@5.3.3':
resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==}
'@types/react-router@5.1.20':
resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==}
'@types/react@18.3.12': '@types/react@18.3.12':
resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==}
@ -666,6 +663,12 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
ahooks@3.8.2:
resolution: {integrity: sha512-iuYD3PWopdw9HqH++3ul6/Oxl9Q9/tP+np4yiYd0mIzN3QfDKnyII28MWUcmSkaHF415R6bUcrl0vD/80NNogg==}
engines: {node: '>=8.0.0'}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
ajv@6.12.6: ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
@ -739,6 +742,9 @@ packages:
classnames@2.5.1: classnames@2.5.1:
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
clsx@2.1.1: clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -763,6 +769,10 @@ packages:
constant-case@3.0.4: constant-case@3.0.4:
resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==}
cookie@1.0.2:
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
engines: {node: '>=18'}
cross-spawn@7.0.5: cross-spawn@7.0.5:
resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==} resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -777,6 +787,9 @@ packages:
csstype@3.1.3: csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
dayjs@1.11.13:
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
debug@4.3.7: debug@4.3.7:
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@ -976,12 +989,6 @@ packages:
header-case@2.0.4: header-case@2.0.4:
resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==}
history@4.10.1:
resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==}
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
html-url-attributes@3.0.1: html-url-attributes@3.0.1:
resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==}
@ -1000,6 +1007,9 @@ packages:
inline-style-parser@0.2.4: inline-style-parser@0.2.4:
resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
intersection-observer@0.12.2:
resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==}
is-alphabetical@2.0.1: is-alphabetical@2.0.1:
resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==}
@ -1028,9 +1038,6 @@ packages:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'} engines: {node: '>=12'}
isarray@0.0.1:
resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==}
isexe@2.0.0: isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@ -1046,6 +1053,10 @@ packages:
react: react:
optional: true optional: true
js-cookie@3.0.5:
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
engines: {node: '>=14'}
js-tokens@4.0.0: js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@ -1256,9 +1267,6 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'} engines: {node: '>=8'}
path-to-regexp@1.9.0:
resolution: {integrity: sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==}
picocolors@1.1.1: picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@ -1333,15 +1341,15 @@ packages:
react: ^16.8.0 || ^17 || ^18 react: ^16.8.0 || ^17 || ^18
react-dom: ^16.8.0 || ^17 || ^18 react-dom: ^16.8.0 || ^17 || ^18
react-router-dom@5.3.4: react-router@7.0.1:
resolution: {integrity: sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==} resolution: {integrity: sha512-WVAhv9oWCNsja5AkK6KLpXJDSJCQizOIyOd4vvB/+eHGbYx5vkhcmcmwWjQ9yqkRClogi+xjEg9fNEOd5EX/tw==}
peerDependencies: engines: {node: '>=20.0.0'}
react: '>=15'
react-router@5.3.4:
resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==}
peerDependencies: peerDependencies:
react: '>=15' react: '>=18'
react-dom: '>=18'
peerDependenciesMeta:
react-dom:
optional: true
react-toastify@10.0.6: react-toastify@10.0.6:
resolution: {integrity: sha512-yYjp+omCDf9lhZcrZHKbSq7YMuK0zcYkDFTzfRFgTXkTFHZ1ToxwAonzA4JI5CxA91JpjFLmwEsZEgfYfOqI1A==} resolution: {integrity: sha512-yYjp+omCDf9lhZcrZHKbSq7YMuK0zcYkDFTzfRFgTXkTFHZ1ToxwAonzA4JI5CxA91JpjFLmwEsZEgfYfOqI1A==}
@ -1378,13 +1386,13 @@ packages:
remark-rehype@11.1.1: remark-rehype@11.1.1:
resolution: {integrity: sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==} resolution: {integrity: sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==}
resize-observer-polyfill@1.5.1:
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
resolve-from@4.0.0: resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'} engines: {node: '>=4'}
resolve-pathname@3.0.0:
resolution: {integrity: sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==}
reusify@1.0.4: reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'} engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
@ -1400,6 +1408,10 @@ packages:
scheduler@0.23.2: scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
screenfull@5.2.0:
resolution: {integrity: sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==}
engines: {node: '>=0.10.0'}
semver@7.6.3: semver@7.6.3:
resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -1408,6 +1420,9 @@ packages:
sentence-case@3.0.4: sentence-case@3.0.4:
resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==}
set-cookie-parser@2.7.1:
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
shallowequal@1.1.0: shallowequal@1.1.0:
resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
@ -1453,11 +1468,10 @@ packages:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'} engines: {node: '>=8'}
tiny-invariant@1.3.3: swr@2.2.5:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} resolution: {integrity: sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==}
peerDependencies:
tiny-warning@1.0.3: react: ^16.11.0 || ^17.0.0 || ^18.0.0
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
to-regex-range@5.0.1: to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
@ -1481,6 +1495,9 @@ packages:
tslib@2.6.3: tslib@2.6.3:
resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
turbo-stream@2.4.0:
resolution: {integrity: sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==}
type-check@0.4.0: type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@ -1534,9 +1551,6 @@ packages:
peerDependencies: peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0
value-equal@1.0.1:
resolution: {integrity: sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==}
vfile-message@4.0.2: vfile-message@4.0.2:
resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==}
@ -1890,6 +1904,8 @@ snapshots:
dependencies: dependencies:
'@swc/counter': 0.1.3 '@swc/counter': 0.1.3
'@types/cookie@0.6.0': {}
'@types/debug@4.1.12': '@types/debug@4.1.12':
dependencies: dependencies:
'@types/ms': 0.7.34 '@types/ms': 0.7.34
@ -1904,8 +1920,6 @@ snapshots:
dependencies: dependencies:
'@types/unist': 3.0.3 '@types/unist': 3.0.3
'@types/history@4.7.11': {}
'@types/json-schema@7.0.15': {} '@types/json-schema@7.0.15': {}
'@types/lodash@4.17.13': {} '@types/lodash@4.17.13': {}
@ -1926,17 +1940,6 @@ snapshots:
dependencies: dependencies:
'@types/react': 18.3.12 '@types/react': 18.3.12
'@types/react-router-dom@5.3.3':
dependencies:
'@types/history': 4.7.11
'@types/react': 18.3.12
'@types/react-router': 5.1.20
'@types/react-router@5.1.20':
dependencies:
'@types/history': 4.7.11
'@types/react': 18.3.12
'@types/react@18.3.12': '@types/react@18.3.12':
dependencies: dependencies:
'@types/prop-types': 15.7.13 '@types/prop-types': 15.7.13
@ -2044,6 +2047,19 @@ snapshots:
acorn@8.14.0: {} acorn@8.14.0: {}
ahooks@3.8.2(react@18.3.1):
dependencies:
'@babel/runtime': 7.26.0
dayjs: 1.11.13
intersection-observer: 0.12.2
js-cookie: 3.0.5
lodash: 4.17.21
react: 18.3.1
react-fast-compare: 3.2.2
resize-observer-polyfill: 1.5.1
screenfull: 5.2.0
tslib: 2.6.3
ajv@6.12.6: ajv@6.12.6:
dependencies: dependencies:
fast-deep-equal: 3.1.3 fast-deep-equal: 3.1.3
@ -2133,6 +2149,8 @@ snapshots:
classnames@2.5.1: {} classnames@2.5.1: {}
client-only@0.0.1: {}
clsx@2.1.1: {} clsx@2.1.1: {}
color-convert@2.0.1: color-convert@2.0.1:
@ -2155,6 +2173,8 @@ snapshots:
tslib: 2.6.3 tslib: 2.6.3
upper-case: 2.0.2 upper-case: 2.0.2
cookie@1.0.2: {}
cross-spawn@7.0.5: cross-spawn@7.0.5:
dependencies: dependencies:
path-key: 3.1.1 path-key: 3.1.1
@ -2171,6 +2191,8 @@ snapshots:
csstype@3.1.3: {} csstype@3.1.3: {}
dayjs@1.11.13: {}
debug@4.3.7: debug@4.3.7:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@ -2407,19 +2429,6 @@ snapshots:
capital-case: 1.0.4 capital-case: 1.0.4
tslib: 2.6.3 tslib: 2.6.3
history@4.10.1:
dependencies:
'@babel/runtime': 7.26.0
loose-envify: 1.4.0
resolve-pathname: 3.0.0
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
value-equal: 1.0.1
hoist-non-react-statics@3.3.2:
dependencies:
react-is: 16.13.1
html-url-attributes@3.0.1: {} html-url-attributes@3.0.1: {}
ignore@5.3.2: {} ignore@5.3.2: {}
@ -2433,6 +2442,8 @@ snapshots:
inline-style-parser@0.2.4: {} inline-style-parser@0.2.4: {}
intersection-observer@0.12.2: {}
is-alphabetical@2.0.1: {} is-alphabetical@2.0.1: {}
is-alphanumerical@2.0.1: is-alphanumerical@2.0.1:
@ -2454,8 +2465,6 @@ snapshots:
is-plain-obj@4.1.0: {} is-plain-obj@4.1.0: {}
isarray@0.0.1: {}
isexe@2.0.0: {} isexe@2.0.0: {}
jotai@2.10.3(@types/react@18.3.12)(react@18.3.1): jotai@2.10.3(@types/react@18.3.12)(react@18.3.1):
@ -2463,6 +2472,8 @@ snapshots:
'@types/react': 18.3.12 '@types/react': 18.3.12
react: 18.3.1 react: 18.3.1
js-cookie@3.0.5: {}
js-tokens@4.0.0: {} js-tokens@4.0.0: {}
js-yaml@4.1.0: js-yaml@4.1.0:
@ -2811,10 +2822,6 @@ snapshots:
path-key@3.1.1: {} path-key@3.1.1: {}
path-to-regexp@1.9.0:
dependencies:
isarray: 0.0.1
picocolors@1.1.1: {} picocolors@1.1.1: {}
picomatch@2.3.1: {} picomatch@2.3.1: {}
@ -2893,29 +2900,15 @@ snapshots:
react-fast-compare: 3.2.2 react-fast-compare: 3.2.2
warning: 4.0.3 warning: 4.0.3
react-router-dom@5.3.4(react@18.3.1): react-router@7.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@babel/runtime': 7.26.0
history: 4.10.1
loose-envify: 1.4.0
prop-types: 15.8.1
react: 18.3.1
react-router: 5.3.4(react@18.3.1)
tiny-invariant: 1.3.3
tiny-warning: 1.0.3
react-router@5.3.4(react@18.3.1):
dependencies: dependencies:
'@babel/runtime': 7.26.0 '@types/cookie': 0.6.0
history: 4.10.1 cookie: 1.0.2
hoist-non-react-statics: 3.3.2
loose-envify: 1.4.0
path-to-regexp: 1.9.0
prop-types: 15.8.1
react: 18.3.1 react: 18.3.1
react-is: 16.13.1 set-cookie-parser: 2.7.1
tiny-invariant: 1.3.3 turbo-stream: 2.4.0
tiny-warning: 1.0.3 optionalDependencies:
react-dom: 18.3.1(react@18.3.1)
react-toastify@10.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): react-toastify@10.0.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
@ -2962,9 +2955,9 @@ snapshots:
unified: 11.0.5 unified: 11.0.5
vfile: 6.0.3 vfile: 6.0.3
resolve-from@4.0.0: {} resize-observer-polyfill@1.5.1: {}
resolve-pathname@3.0.0: {} resolve-from@4.0.0: {}
reusify@1.0.4: {} reusify@1.0.4: {}
@ -3000,6 +2993,8 @@ snapshots:
dependencies: dependencies:
loose-envify: 1.4.0 loose-envify: 1.4.0
screenfull@5.2.0: {}
semver@7.6.3: {} semver@7.6.3: {}
sentence-case@3.0.4: sentence-case@3.0.4:
@ -3008,6 +3003,8 @@ snapshots:
tslib: 2.6.3 tslib: 2.6.3
upper-case-first: 2.0.2 upper-case-first: 2.0.2
set-cookie-parser@2.7.1: {}
shallowequal@1.1.0: {} shallowequal@1.1.0: {}
shebang-command@2.0.0: shebang-command@2.0.0:
@ -3056,9 +3053,11 @@ snapshots:
dependencies: dependencies:
has-flag: 4.0.0 has-flag: 4.0.0
tiny-invariant@1.3.3: {} swr@2.2.5(react@18.3.1):
dependencies:
tiny-warning@1.0.3: {} client-only: 0.0.1
react: 18.3.1
use-sync-external-store: 1.2.2(react@18.3.1)
to-regex-range@5.0.1: to-regex-range@5.0.1:
dependencies: dependencies:
@ -3076,6 +3075,8 @@ snapshots:
tslib@2.6.3: {} tslib@2.6.3: {}
turbo-stream@2.4.0: {}
type-check@0.4.0: type-check@0.4.0:
dependencies: dependencies:
prelude-ls: 1.2.1 prelude-ls: 1.2.1
@ -3144,8 +3145,6 @@ snapshots:
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
value-equal@1.0.1: {}
vfile-message@4.0.2: vfile-message@4.0.2:
dependencies: dependencies:
'@types/unist': 3.0.3 '@types/unist': 3.0.3

BIN
public/Alibaba-PuHuiTi-Heavy.ttf

Binary file not shown.

3
public/data.json

@ -0,0 +1,3 @@
{
"a": "FUCK"
}

56
src/App.tsx

@ -1,29 +1,33 @@
import AppRouter from "@/router/AppRouter" import { HashRouter, Navigate, Route, Routes } from "react-router"
import { ToastContainer, Bounce } from 'react-toastify'; import { ToastContainer, Bounce } from "react-toastify"
import BaseLayout from "@/layout/base"
import Home from "@/views/Home"
import NoMatch from "@/viewsSys/NoMatch"
import AccountStore from "@/store/account"
export default function App() { export default function App() {
return <> AccountStore.initUser()
<AppRouter></AppRouter> return (
<ToastContainer <>
position="bottom-right" <HashRouter>
autoClose={5000} <Routes>
hideProgressBar <Route path="/" element={<BaseLayout />}>
closeOnClick={false} <Route index element={<Navigate to="home" replace />} />
pauseOnFocusLoss <Route path="home" element={<Home />} />
pauseOnHover <Route path="*" element={<NoMatch />} />
theme="light" </Route>
transition={Bounce} </Routes>
/> </HashRouter>
{/* <ToastContainer <ToastContainer
stacked position="bottom-right"
position="bottom-right" autoClose={5000}
autoClose={5000} hideProgressBar
hideProgressBar closeOnClick={false}
closeOnClick={false} pauseOnFocusLoss
pauseOnFocusLoss pauseOnHover
pauseOnHover theme="light"
theme="light" transition={Bounce}
transition={Bounce} />
/> */} </>
</> )
} }

15
src/api/_utils/index.ts

@ -0,0 +1,15 @@
import { Account, Client, ID } from "appwrite"
import { toast } from "react-toastify"
const client = new Client()
client.setProject(import.meta.env.VUE_APPWRITE_PROJECT_ID)
export async function apiRegister(opts: { email: string; password: string }, errText: string) {
const account = new Account(client)
try {
await account.create(ID.unique(), opts.email, opts.password)
} catch (error: any) {
toast.error(error?.message ?? errText)
return Promise.reject(error)
}
}

57
src/api/http.ts

@ -0,0 +1,57 @@
import { Account, Client, ID } from "appwrite"
import { toast } from "react-toastify"
const client = new Client()
client.setProject(import.meta.env.VITE_APP_WRITE_PROJECT_ID)
export async function apiRegister(opts: { email: string; password: string }, errText?: string) {
const account = new Account(client)
try {
await account.create(ID.unique(), opts.email, opts.password)
} catch (error: any) {
toast.error(error?.message ?? errText)
return Promise.reject(error)
}
}
export async function apiLogin(opts: { email: string; password: string }, errText?: string) {
const account = new Account(client)
try {
return await account.createEmailPasswordSession(opts.email, opts.password);
} catch (error: any) {
toast.error(error?.message ?? errText)
return Promise.reject(error)
}
}
async function checkLogin() {
try {
await getAccount()
return true
} catch (error) {
return false
}
}
export async function listSessions(errText?: string) {
const account = new Account(client)
try {
return await await account.listSessions();
} catch (error: any) {
toast.error(error?.message ?? errText)
return Promise.reject(error)
}
}
export async function getAccount(errText?: string) {
const account = new Account(client)
try {
return await await account.get();
} catch (error: any) {
toast.error(error?.message ?? errText)
return Promise.reject(error)
}
}

17
src/api/index.ts

@ -1,15 +1,4 @@
import { Account, Client, ID } from "appwrite" import * as Http from "./http"
import { toast } from "react-toastify"
const client = new Client()
client.setProject(import.meta.env.VUE_APPWRITE_PROJECT_ID) // export * from "./http"
export default Http
export async function apiRegister(opts: { email: string; password: string }, errText: string) {
const account = new Account(client)
try {
await account.create(ID.unique(), opts.email, opts.password)
} catch (error: any) {
toast.error(error?.message ?? errText)
return Promise.reject(error)
}
}

17
src/index.css

@ -4,12 +4,23 @@
@import "@blueprintjs/icons/lib/css/blueprint-icons.css"; @import "@blueprintjs/icons/lib/css/blueprint-icons.css";
@import "@blueprintjs/table/lib/css/table.css"; @import "@blueprintjs/table/lib/css/table.css";
html,body, #root{ @font-face {
font-family: "Alibaba";
src: url("/Alibaba-PuHuiTi-Heavy.ttf") format("woff");
}
html,
body,
#root {
height: 100%; height: 100%;
} }
body {
height: 100%;
/* font-family: Alibaba; */
}
.container { .container {
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
} }

35
src/layout/base.tsx

@ -1,15 +1,17 @@
import { Alignment, Button, Dialog, DialogBody, DialogFooter, Menu, MenuDivider, MenuItem, Navbar, Popover } from "@blueprintjs/core" import { Alignment, Button, Dialog, DialogBody, DialogFooter, Menu, MenuDivider, MenuItem, Navbar, Popover } from "@blueprintjs/core"
import { ReactNode, useState } from "react" import { ReactNode, useState } from "react"
import { NavLink, useHistory } from "react-router-dom" import { NavLink, Outlet } from "react-router"
import styled from "styled-components" import styled from "styled-components"
import { GlobalStyles } from "./GlobalStyles" import { GlobalStyles } from "./GlobalStyles"
import { Notice } from "@/ui/Notice" import { Notice } from "@/ui/Notice"
import { Markdown } from "@/ui/Markdown" import { Markdown } from "@/ui/Markdown"
import { Register } from "@/ui/Register/Register" import { Register } from "@/ui/Register/Register"
import { Login } from "@/ui/Login/Login" import { Login } from "@/ui/Login/Login"
import AccountStore from "@/store/account"
import { useAtom } from "jotai"
interface PageProps { interface PageProps {
children: ReactNode // children: ReactNode
} }
const PageWrapper = styled.div` const PageWrapper = styled.div`
@ -30,8 +32,7 @@ function BaseLayout(props: PageProps) {
const [isOpenAbout, setIsOpenAbout] = useState(false) const [isOpenAbout, setIsOpenAbout] = useState(false)
const [isOpenAuth, setIsOpenAuth] = useState(false) const [isOpenAuth, setIsOpenAuth] = useState(false)
const [isRegister, setIsRegister] = useState(false) const [isRegister, setIsRegister] = useState(false)
const [user] = useAtom(AccountStore.userStore)
const router = useHistory()
const about = ` const about = `
> 退 > 退
@ -50,7 +51,7 @@ function BaseLayout(props: PageProps) {
<Navbar.Group align={Alignment.LEFT}> <Navbar.Group align={Alignment.LEFT}>
<Navbar.Heading></Navbar.Heading> <Navbar.Heading></Navbar.Heading>
<Navbar.Divider /> <Navbar.Divider />
<NavLink to={"/home"} strict exact activeClassName="actived"> <NavLink to={"/home"}>
<Button className="bp5-minimal" icon="home" text="首页" /> <Button className="bp5-minimal" icon="home" text="首页" />
</NavLink> </NavLink>
<Popover <Popover
@ -59,8 +60,8 @@ function BaseLayout(props: PageProps) {
onInteraction={isOpen => setIsOpen(isOpen)} onInteraction={isOpen => setIsOpen(isOpen)}
content={ content={
<Menu> <Menu>
<MenuItem icon="flow-review-branch" text="天涯笔记" disabled onClick={() => router.push("/project")} /> <MenuItem icon="flow-review-branch" text="天涯笔记" disabled />
<MenuItem icon="third-party" text="全聚德" disabled onClick={() => router.push("/project/child")} /> <MenuItem icon="third-party" text="全聚德" disabled />
<MenuDivider /> <MenuDivider />
<MenuItem icon="document" text="文档"> <MenuItem icon="document" text="文档">
<MenuItem icon="build" text="CSS选择器示例" /> <MenuItem icon="build" text="CSS选择器示例" />
@ -81,14 +82,22 @@ function BaseLayout(props: PageProps) {
<Notice /> <Notice />
</Navbar.Group> </Navbar.Group>
<Navbar.Group align={Alignment.RIGHT}> <Navbar.Group align={Alignment.RIGHT}>
<Button icon="user" className="bp5-minimal" text="登录 / 注册" onClick={() => setIsOpenAuth(true)} /> {
<Navbar.Divider /> !user.isLogin && (
<NavLink to={"/about"}> <>
<Button onClick={() => setIsOpenAbout(true)} className="bp5-minimal" text="关于" /> <Button icon="user" className="bp5-minimal" text="登录 / 注册" onClick={() => setIsOpenAuth(true)} />
</NavLink> <Navbar.Divider />
</>
)
}
{/* <NavLink to={"/about"}> */}
<Button onClick={() => setIsOpenAbout(true)} className="bp5-minimal" text="关于" />
{/* </NavLink> */}
</Navbar.Group> </Navbar.Group>
</Navbar> </Navbar>
<ContentWrapper>{props.children}</ContentWrapper> <ContentWrapper>
<Outlet />
</ContentWrapper>
<Dialog isOpen={isOpenAbout} title="关于我" icon="info-sign" onClose={() => setIsOpenAbout(false)}> <Dialog isOpen={isOpenAbout} title="关于我" icon="info-sign" onClose={() => setIsOpenAbout(false)}>
<DialogBody> <DialogBody>
<Markdown>{about}</Markdown> <Markdown>{about}</Markdown>

72
src/plugins/http/base.ts

@ -25,37 +25,58 @@ export class Plugin implements IPlugin {
destory() { } destory() { }
} }
export const enum EFor {
Continue,
Break,
}
export abstract class PluginsManager { export abstract class PluginsManager {
static plugins: IPlugin[] = [] static plugins: IPlugin[] = []
static use(plugin: IPlugin) { static use(plugin: IPlugin | IPlugin[]) {
if (Array.isArray(plugin)) { if (Array.isArray(plugin)) {
PluginsManager.plugins = this.plugins.concat(plugin) PluginsManager.plugins = this.plugins.concat(plugin)
} else PluginsManager.plugins.push(plugin) } else PluginsManager.plugins.push(plugin)
} }
plugins: IPlugin[] = [] plugins: IPlugin[] = []
exculdPlugins: string[] = []
use(plugin: IPlugin) { use(plugin: IPlugin) {
if (Array.isArray(plugin)) { if (Array.isArray(plugin)) {
this.plugins = this.plugins.concat(plugin) this.plugins = this.plugins.concat(plugin)
} else this.plugins.push(plugin) } else this.plugins.push(plugin)
} }
callPluginByName<T>(name: string, key: keyof T, ...argus: any[]) { async runPlugins(cb: (p: IPlugin) => Promise<EFor | undefined>) {
const array = [...PluginsManager.plugins, ...this.plugins]
for (let i = 0; i < array.length; i++) {
let p = array[i]
let result = await cb(p)
if (result === EFor.Continue) {
continue
} else if (result === EFor.Break) {
break
}
}
}
async _callPluginByName<T>(name: string, key: keyof T, ...argus: any[]) {
const array = [...PluginsManager.plugins, ...this.plugins] const array = [...PluginsManager.plugins, ...this.plugins]
for (let i = 0; i < array.length; i++) { for (let i = 0; i < array.length; i++) {
let p = array[i] let p = array[i]
if (this.exculdPlugins.includes(p.name)) continue
if (!p.name) continue if (!p.name) continue
if (name === p.name) { if (name === p.name) {
const fn = (p as T)[key] const fn = (p as T)[key]
typeof fn === "function" && fn.apply(p, argus) typeof fn === "function" && await fn.apply(p, argus)
} }
} }
} }
callPlugin(key: keyof IPlugin, ...argus: any[]) { async _callPlugin(key: keyof IPlugin, ...argus: any[]) {
const array = [...PluginsManager.plugins, ...this.plugins] const array = [...PluginsManager.plugins, ...this.plugins]
for (let i = 0; i < array.length; i++) { for (let i = 0; i < array.length; i++) {
let p = array[i] let p = array[i]
if (this.exculdPlugins.includes(p.name)) continue
const fn = p[key] const fn = p[key]
typeof fn === "function" && fn.apply(p, argus) typeof fn === "function" && await fn.apply(p, argus)
} }
} }
} }
@ -66,25 +87,46 @@ export abstract class httpBase extends PluginsManager {
requestInterceptorId: null | number = null requestInterceptorId: null | number = null
responseInterceptorId: null | number = null responseInterceptorId: null | number = null
async callPluginByName<T>(name: string, key: keyof T, ...argus: any[]) {
await this.runPlugins(async (p) => {
if (this.exculdPlugins.includes(p.name)) return EFor.Continue
if (!p.name) return EFor.Continue
if (name === p.name) {
const fn = (p as T)[key]
typeof fn === "function" && await fn.apply(p, argus)
}
})
// await this._callPluginByName<T>(name, key, ...argus)
}
async callPlugin(key: keyof IPlugin, ...argus: any[]) {
await this.runPlugins(async (p) => {
if (this.exculdPlugins.includes(p.name)) return EFor.Continue
const fn = p[key]
typeof fn === "function" && await fn.apply(p, argus)
})
// await this._callPlugin(key, ...argus)
}
create<T>(config?: CreateAxiosDefaults<T>) { create<T>(config?: CreateAxiosDefaults<T>) {
this.instance = axios.create(deepAssign<CreateAxiosDefaults<T>>(axios.defaults, config ?? {})) this.instance = axios.create(deepAssign<CreateAxiosDefaults<T>>(axios.defaults, config ?? {}))
this.requestInterceptorId = this.instance.interceptors.request.use(config => { this.requestInterceptorId = this.instance.interceptors.request.use(async config => {
const argu = { config } const argu = { config }
this.callPlugin("beforeRequestConfig", argu) await this.callPlugin("beforeRequestConfig", argu)
return argu.config return argu.config
}, error => { }, async error => {
const argu = { error } const argu = { error }
this.callPlugin("beforeRequestError", argu) await this.callPlugin("beforeRequestError", argu)
return Promise.reject(error) return Promise.reject(argu.error)
}) })
this.responseInterceptorId = this.instance.interceptors.response.use(response => { this.responseInterceptorId = this.instance.interceptors.response.use(async response => {
const argu = { response } const argu = { response }
this.callPlugin("beforeResponse", argu) await this.callPlugin("beforeResponse", argu)
return Promise.resolve(argu.response) return Promise.resolve(argu.response)
}, (error) => { }, async (error) => {
const argu = { error } const argu = { error }
this.callPlugin("beforeResponseError", argu) await this.callPlugin("beforeResponseError", argu)
return Promise.reject(error) return Promise.reject(argu.error)
}) })
return this.instance return this.instance
} }

76
src/plugins/http/index.ts

@ -1,10 +1,25 @@
import { httpBase, IPlugin } from "./base" import { httpBase, IPlugin } from "./base"
import { CreateAxiosDefaults, AxiosRequestConfig, AxiosResponse } from "axios" import { CreateAxiosDefaults, AxiosRequestConfig, AxiosResponse } from "axios"
import { RepeatPlugin } from "./Repeat"
const FlyPoll: Map<string, any> = new Map() const FlyPoll: Map<string, any> = new Map()
interface ICallFly {
pass: (argus: { exculdPlugins?: string[] }) => Fly
get: <T = any, Data = unknown>(...argus: [url: string, config?: AxiosRequestConfig<Data> | undefined]) => () => Promise<AxiosResponse<T>>
post: <T = any, Data = unknown>(...argus: [url: string, config?: AxiosRequestConfig<Data> | undefined]) => () => Promise<AxiosResponse<T>>
put: <T = any, Data = unknown>(...argus: [url: string, config?: AxiosRequestConfig<Data> | undefined]) => () => Promise<AxiosResponse<T>>
delete: <T = any, Data = unknown>(...argus: [url: string, config?: AxiosRequestConfig<Data> | undefined]) => () => Promise<AxiosResponse<T>>
request: <T = any, Data = unknown>(...argus: [config: AxiosRequestConfig<Data>]) => () => Promise<AxiosResponse<T>>
}
class Fly extends httpBase { class Fly extends httpBase {
static disposeAll() {
if (FlyPoll.size) {
Array.from(FlyPoll.keys()).forEach(v => {
Fly.dispose(v)
})
}
}
static dispose(name: string) { static dispose(name: string) {
if (FlyPoll.has(name)) { if (FlyPoll.has(name)) {
const instance = FlyPoll.get(name) const instance = FlyPoll.get(name)
@ -23,9 +38,28 @@ class Fly extends httpBase {
static invoke(name?: string): Fly { static invoke(name?: string): Fly {
if (!name) name = "$defalut" if (!name) name = "$defalut"
const instance = FlyPoll.get(name) const instance = FlyPoll.get(name)
if (!instance) throw new Error("未初始化此实例") if (!instance) {
throw new Error("未初始化此实例")
}
instance.exculdPlugins = []
return instance return instance
} }
static callFn(name?: string): ICallFly {
if (!name) name = "$defalut"
const instance = FlyPoll.get(name)
if (!instance) {
throw new Error("未初始化此实例")
}
instance.exculdPlugins = []
return new Proxy(instance, {
get(target, p: string) {
if (["get", "post", "put", "delete", "request"].includes(p.toLowerCase())) {
return (...argus: any[]) => () => target[p](...argus)
}
return target[p]
},
})
}
static get method() { static get method() {
return { return {
@ -44,13 +78,18 @@ class Fly extends httpBase {
} }
default: CreateAxiosDefaults = { default: CreateAxiosDefaults = {
// baseURL: process.env.VUE_APP_BASEURL, baseURL: import.meta.env.BASE_URL,
timeout: 10000, timeout: 10000,
headers: { headers: {
'Content-Type': Fly.contentType.FORM, 'Content-Type': Fly.contentType.FORM,
} }
} }
pass({ exculdPlugins }: { exculdPlugins?: string[] }) {
this.exculdPlugins = exculdPlugins ?? []
return this
}
name: string name: string
constructor(name: string) { constructor(name: string) {
@ -72,37 +111,18 @@ class Fly extends httpBase {
request<T = any, Data = unknown>(...argus: [config: AxiosRequestConfig<Data>]) { request<T = any, Data = unknown>(...argus: [config: AxiosRequestConfig<Data>]) {
return this.instance!.request.apply(this.instance, argus) as Promise<AxiosResponse<T>> return this.instance!.request.apply(this.instance, argus) as Promise<AxiosResponse<T>>
} }
#init(config: AxiosRequestConfig) { async #init(config: AxiosRequestConfig) {
this.callPlugin("beforeCreate") await this.callPlugin("beforeCreate")
this.create(config) this.create(config)
this.callPlugin("created") await this.callPlugin("created")
} }
#destory() { async #destory() {
this.callPlugin("beforeDestory") await this.callPlugin("beforeDestory")
this.destory() this.destory()
this.callPlugin("destory") await this.callPlugin("destory")
} }
} }
export { export {
Fly Fly
} }
// https://api.52vmy.cn/
// Fly.invoke().request({ method: "get", url: "http://localhost:5173/", global: false }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke().request({ method: "get", url: "http://localhost:5173/", global: true }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke().request({ method: "get", url: "https://api.52vmy.cn/api/wl/word/bing/tu", global: true }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke().request({ method: "get", url: "https://api.52vmy.cn/api/wl/word/bing/tu", global: true }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke("empty").request({ method: "get", url: "https://api.52vmy.cn/api/wl/yan/bay" }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke("empty").request({ method: "get", url: "https://api.52vmy.cn/api/img/tu/girl" }).then((res) => console.log(res.data)).catch(console.log)
// setTimeout(()=>{
// // Fly.invoke("empty").request({method: "get", url: "https://api.52vmy.cn/api/img/tu/man"}).then((res)=>console.log(res.data)).catch(console.log)
// Fly.invoke().callPluginByName<RepeatPlugin>(RepeatPlugin.name, "clearPendingPool")
// }, 0)

0
src/plugins/http/plugins.ts

133
src/plugins/http/plugins/Loading.ts

@ -0,0 +1,133 @@
import { AxiosRequestConfig, AxiosResponse, AxiosError } from "axios"
import { IPlugin } from "../base"
import { Id, toast } from "react-toastify"
declare module "axios" {
interface AxiosRequestConfig {
loadingAttrs?: Partial<IConfig>
}
}
type AxiosRequestConfigPlus = AxiosRequestConfig & {
$loading_ToastID?: Id
$loading_CreateTimeStamp?: number
$loading_ToastShowFn?: () => void
$loading_ShowTimerId?: NodeJS.Timeout
}
interface IConfig {
text: string
min: number
minShow: boolean
minSync: boolean
minShowLong: number
}
// 取消重复请求
export class LoadingPlugin implements IPlugin {
static name: string = "loading"
name: string = "loading"
defaultConfig: IConfig = {
text: "加载中",
min: 1000,
minShow: false,
minSync: true,
minShowLong: 1000,
}
config: IConfig = JSON.parse(JSON.stringify(this.defaultConfig))
constructor(config: Partial<IConfig> = {}) {
; (Object.keys(config) as (keyof IConfig)[]).forEach(v => {
if (config[v]) {
(this.config as any)[v] = config[v]
}
})
}
getConfig<T extends keyof IConfig>(key: T, config: Partial<IConfig> = {}) {
const keys = Object.keys(config) as T[]
for (let i = 0; i < keys.length; i++) {
const v = keys[i];
if (v === key) {
return (config as IConfig)[key]
}
}
return this.config[key]
}
beforeRequestConfig({ config }: { config: AxiosRequestConfigPlus }) {
const text = this.getConfig("text", config.loadingAttrs)
config.$loading_ToastShowFn = () => {
const id = toast.loading(text)
config.$loading_CreateTimeStamp = new Date().getTime()
config.$loading_ToastID = id
}
if (!this.getConfig("minShow", config.loadingAttrs)) {
config.$loading_ToastShowFn()
delete config.$loading_ToastShowFn
} else {
config.$loading_ShowTimerId = setTimeout(() => {
config.$loading_ToastShowFn!()
delete config.$loading_ToastShowFn
}, this.getConfig("min", config.loadingAttrs));
}
}
beforeResponse({ response }: { response: AxiosResponse }) {
return new Promise((resolve) => {
const over = (isOver: boolean) => {
if (isOver) {
resolve(void 0)
}
}
const { config } = response as { config: AxiosRequestConfigPlus }
clearTimeout(config.$loading_ShowTimerId)
if (!this.getConfig("minShow", config.loadingAttrs)) {
const min = this.getConfig("min", config.loadingAttrs)
if (config.$loading_ToastID) {
const [ToastID, showTimeStamp] = [config.$loading_ToastID, config.$loading_CreateTimeStamp]
const oft = new Date().getTime() - showTimeStamp!
if (oft < min) {
setTimeout(() => {
toast.dismiss(ToastID)
over(this.getConfig("minSync", config.loadingAttrs))
}, min - oft);
} else {
over(this.getConfig("minSync", config.loadingAttrs))
toast.dismiss(ToastID)
}
delete config.$loading_ToastID
delete config.$loading_CreateTimeStamp
}
} else {
if (config.$loading_ToastID) {
const min = this.getConfig("minShowLong", config.loadingAttrs)
const [ToastID, showTimeStamp] = [config.$loading_ToastID, config.$loading_CreateTimeStamp]
const oft = new Date().getTime() - showTimeStamp!
if (oft < min) {
setTimeout(() => {
toast.dismiss(ToastID)
over(this.getConfig("minSync", config.loadingAttrs))
}, min - oft);
} else {
over(this.getConfig("minSync", config.loadingAttrs))
toast.dismiss(ToastID)
}
delete config.$loading_ToastID
delete config.$loading_CreateTimeStamp
}
}
over(!this.getConfig("minSync", config.loadingAttrs))
})
}
beforeResponseError(argu: { error: AxiosError }) {
const requestConfig = argu.error.config! as AxiosRequestConfigPlus
clearTimeout(requestConfig.$loading_ShowTimerId)
if (requestConfig.$loading_ToastID) {
const [ToastID] = [requestConfig.$loading_ToastID, requestConfig.$loading_CreateTimeStamp]
toast.dismiss(ToastID)
delete requestConfig.$loading_ToastID
delete requestConfig.$loading_CreateTimeStamp
}
}
}

36
src/plugins/http/Repeat.ts → src/plugins/http/plugins/Repeat.ts

@ -1,5 +1,5 @@
import { isCancel, AxiosRequestConfig, AxiosResponse, AxiosError } from "axios" import { isCancel, AxiosRequestConfig, AxiosResponse, AxiosError } from "axios"
import { IPlugin } from "./base" import { IPlugin } from "../base"
declare module "axios" { declare module "axios" {
interface AxiosRequestConfig { interface AxiosRequestConfig {
@ -7,14 +7,33 @@ declare module "axios" {
* RepeatPlugin插件的clearPendingPool清除 * RepeatPlugin插件的clearPendingPool清除
*/ */
global?: boolean global?: boolean
cancelAttrs?: Partial<IConfig>
} }
} }
interface IConfig {
text: string
}
// 取消重复请求 // 取消重复请求
export class RepeatPlugin implements IPlugin { export class RepeatPlugin implements IPlugin {
static name: string = "repeat" static name: string = "repeat"
name: string = "repeat" name: string = "repeat"
pendingPool = new Map() pendingPool = new Map()
defaultConfig: IConfig = {
text: "${url}请求取消"
}
config: IConfig = JSON.parse(JSON.stringify(this.defaultConfig))
constructor(config: Partial<IConfig> = {}) {
; (Object.keys(config) as (keyof IConfig)[]).forEach(v => {
if (config[v]) {
this.config[v] = config[v]
}
})
}
clearPendingPool(whiteList: string[] = []) { clearPendingPool(whiteList: string[] = []) {
if (!this.pendingPool.size) return if (!this.pendingPool.size) return
const pendingUrlList = Array.from(this.pendingPool.keys()).filter(url => !whiteList.includes(url)) const pendingUrlList = Array.from(this.pendingPool.keys()).filter(url => !whiteList.includes(url))
@ -22,7 +41,7 @@ export class RepeatPlugin implements IPlugin {
pendingUrlList.forEach(pendingUrl => { pendingUrlList.forEach(pendingUrl => {
if (!this.pendingPool.get(pendingUrl).global) { if (!this.pendingPool.get(pendingUrl).global) {
this.pendingPool.get(pendingUrl).cancelFn(`${pendingUrl} 请求取消`) this.pendingPool.get(pendingUrl).cancelFn(`${this.config.text}`.replace(/\$\{(.*?)}/g, (_, t) => t === "url" ? pendingUrl : ''))
this.pendingPool.delete(pendingUrl) this.pendingPool.delete(pendingUrl)
} }
}) })
@ -40,12 +59,13 @@ export class RepeatPlugin implements IPlugin {
const { config } = response const { config } = response
this.pendingPool.delete(config.url) this.pendingPool.delete(config.url)
} }
beforeResponseError({ error }: { error: AxiosError }) { beforeResponseError(argu: { error: AxiosError }) {
const requestConfig = error.config! const requestConfig = argu.error.config!
if (!isCancel(error)) this.pendingPool.delete(requestConfig.url) if (!isCancel(argu.error)) this.pendingPool.delete(requestConfig.url)
if (!error) return if (!argu.error) return
if (isCancel(error)) { if (isCancel(argu.error)) {
throw new Error((requestConfig.signal as AbortSignal)?.reason || error.message || `请求'${requestConfig.url}' 被取消`) argu.error.message = (requestConfig.signal as AbortSignal)?.reason || argu.error.message || `请求'${requestConfig.url}' 被取消`
return
} }
} }
} }

34
src/plugins/request.ts

@ -1,14 +1,40 @@
import { Fly } from "./http" import { Fly } from "./http"
import { RepeatPlugin } from "./http/Repeat" import { RepeatPlugin } from "./http/plugins/Repeat"
import { LoadingPlugin } from "./http/plugins/Loading"
const allPlugin = {
loading: new LoadingPlugin(),
repeat: new RepeatPlugin(),
}
Fly.use([allPlugin.loading])
Fly.init("$defalut", { Fly.init("$defalut", {
timeout: 10000, timeout: 10000,
}, [new RepeatPlugin()]) }, [])
Fly.init("empty", { Fly.init("up", {
timeout: 10000, timeout: 10000,
}) }, [allPlugin.repeat])
// Fly.disposeAll()
// https://api.52vmy.cn/
// Fly.invoke().request({ method: "get", url: "http://localhost:5173/asd", global: false }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke().request({ method: "get", url: "http://localhost:5173/", global: true }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke().request({ method: "get", url: "https://api.52vmy.cn/api/wl/word/bing/tu", global: true }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke().request({ method: "get", url: "https://api.52vmy.cn/api/wl/word/bing/tu", global: true }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke("empty").request({ method: "get", url: "https://api.52vmy.cn/api/wl/yan/bay" }).then((res) => console.log(res.data)).catch(console.log)
// Fly.invoke("empty").request({ method: "get", url: "https://api.52vmy.cn/api/img/tu/girl" }).then((res) => console.log(res.data)).catch(console.log)
// setTimeout(()=>{
// Fly.invoke("empty").request({method: "get", url: "https://api.52vmy.cn/api/img/tu/man"}).then((res)=>console.log(res.data)).catch(console.log)
// Fly.invoke().callPluginByName<RepeatPlugin>(RepeatPlugin.name, "clearPendingPool")
// }, 0)
export { export {
Fly Fly

16
src/router-new/index.ts

@ -0,0 +1,16 @@
import { createHashRouter } from "react-router-dom"
const router = createHashRouter([
{
path: "/",
element: ()=>import("@/views/Home"),
loader: rootLoader,
children: [
{
path: "team",
element: <Team />,
loader: teamLoader,
},
],
},
])

54
src/router/route.tsx

@ -38,33 +38,33 @@ const routesArray = [
// loading: () => <Loading color="blue"></Loading>, // loading: () => <Loading color="blue"></Loading>,
root: true, root: true,
}, },
{ // {
path: "/project", // path: "/project",
component: lazy(() => import("@/views/Project")), // component: lazy(() => import("@/views/Project")),
exact: false, // exact: false,
root: true, // root: true,
meta: { // meta: {
auth: false, // auth: false,
}, // },
children: [ // children: [
{ // {
path: "/project/child", // path: "/project/child",
component: lazy(() => import("@/views/Child")), // component: lazy(() => import("@/views/Child")),
exact: true, // exact: true,
children: [], // children: [],
meta: { // meta: {
auth: true, // auth: true,
}, // },
}, // },
], // ],
}, // },
{ // {
path: "/about", // path: "/about",
component: lazy(() => import("@/views/About")), // component: lazy(() => import("@/views/About")),
exact: true, // exact: true,
root: true, // root: true,
children: [], // children: [],
}, // },
{ {
path: "*", path: "*",
exact: false, exact: false,

48
src/store/account.ts

@ -1,9 +1,45 @@
import { atom } from "jotai" import { atom, useAtom } from "jotai"
import Http from "@/api"
import { useEffect } from "react"
import { atomWithStorage } from 'jotai/utils';
const userStore = { const userStore = atomWithStorage<{
userAtom: atom({ isLogin: boolean
token: "", userInfo: any
}), }>('user', {
isLogin: false,
userInfo: null
});
// const userStore = atom<{
// isLogin: boolean
// userInfo: any
// }>({
// isLogin: false,
// userInfo: null
// });
function initUser() {
const [user, setUser] = useAtom(userStore)
let isRequest = false
useEffect(() => {
if (isRequest) return
isRequest = true
Http.getAccount().then(res => {
setUser({
...user,
isLogin: true,
userInfo: res
})
}).catch(() => {
setUser({
...user,
isLogin: false,
userInfo: false
})
})
}, [])
return [user, setUser]
} }
export { userStore } export default { userStore, initUser }

9
src/ui/Login/Login.tsx

@ -1,3 +1,4 @@
import Http from "@/api"
import { Button, FormGroup, InputGroup, Intent, Tooltip } from "@blueprintjs/core" import { Button, FormGroup, InputGroup, Intent, Tooltip } from "@blueprintjs/core"
import { FC, ReactNode, useCallback, useState } from "react" import { FC, ReactNode, useCallback, useState } from "react"
import { SubmitHandler, useForm } from "react-hook-form" import { SubmitHandler, useForm } from "react-hook-form"
@ -22,8 +23,12 @@ export function Login({ onSuccess, children }: IProps) {
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
} = useForm<Inputs>() } = useForm<Inputs>()
const onSubmit: SubmitHandler<Inputs> = data => { const onSubmit: SubmitHandler<Inputs> = async (data) => {
console.log(data) console.log(await Http.apiLogin({
email: data.email,
password: data.password,
}));
onSuccess && onSuccess() onSuccess && onSuccess()
} }

4
src/ui/Register/Register.tsx

@ -1,6 +1,6 @@
// import { Tag } from "@blueprintjs/core"; // import { Tag } from "@blueprintjs/core";
import { apiRegister } from "@/api" import Http from "@/api"
import { Button, FormGroup, InputGroup, Intent, Tooltip } from "@blueprintjs/core" import { Button, FormGroup, InputGroup, Intent, Tooltip } from "@blueprintjs/core"
import { FC, FormEvent, ReactNode, useCallback, useEffect, useRef, useState } from "react" import { FC, FormEvent, ReactNode, useCallback, useEffect, useRef, useState } from "react"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
@ -33,7 +33,7 @@ export function Register({ onSuccess, children }: IProps) {
if (repeatPassword !== password) return toast.error("两次输入的密码不一致") if (repeatPassword !== password) return toast.error("两次输入的密码不一致")
setIsLoading(true) setIsLoading(true)
try { try {
await toast.promise(apiRegister({ email, password }, "注册失败"), { await toast.promise(Http.apiRegister({ email, password }, "注册失败"), {
pending: '注册中', pending: '注册中',
success: '注册成功', success: '注册成功',
error: '注册失败' error: '注册失败'

18
src/views/About.tsx

@ -1,18 +0,0 @@
import withPage from "@/base/withPage";
import { Button, Dialog, DialogBody, DialogFooter } from "@blueprintjs/core";
import { useCallback, useState } from "react";
function About() {
const [isOpen, setIsOpen] = useState(false);
const toggleOverlay = useCallback(() => setIsOpen(open => !open), [setIsOpen]);
const handleClose = useCallback(() => setIsOpen(false), []);
return <>
<Button text="点击打开美丽的按钮" onClick={toggleOverlay} />
<Dialog isOpen={isOpen} title="关于我" icon="info-sign" onClose={handleClose}>
<DialogBody>{/* body contents here */}</DialogBody>
<DialogFooter actions={<Button intent="primary" text="关闭" onClick={handleClose} />} />
</Dialog>
</>
}
export default withPage(About)

9
src/views/Child.tsx

@ -1,9 +0,0 @@
import { Button } from "@blueprintjs/core";
function Child() {
return <>
<Button text="点击打开美丽的按钮"/>
</>
}
export default Child

47
src/views/Home/index.tsx

@ -1,31 +1,42 @@
import withPage from "@/base/withPage"
import { Hero } from "@/ui/Hero" import { Hero } from "@/ui/Hero"
import { Button } from "@blueprintjs/core" import { Button } from "@blueprintjs/core"
import { ReactNode, useCallback } from "react" import { Fly } from "@/plugins/request"
// import { Fly } from "@/plugins/request" import useSWRMutation from 'swr/mutation'
import { toast } from "react-toastify" import Http from "@/api";
interface IProps { interface IProps {
children: ReactNode // children: ReactNode
} }
export default withPage(function Project({}: IProps) { export default function Home({ }: IProps) {
const onClick = useCallback(() => { const { data, error, trigger, isMutating } = useSWRMutation("/data.json", (url: string) => {
toast.success("Wow so easy !") return Fly.invoke().request<{ a: number }>({
// Fly.invoke().request<{a: number}>({ method: "get",
// method: "get", url: url
// url: "http://api.juheapi.com/japi/toh", })
// global: false }, {
// }).then((res) => console.log(res.data)).catch(console.log) onSuccess(resule, params) {
}, []) console.log(resule, params);
},
onError(resule, params) {
console.log(resule, params);
},
});
const aa = () => {
Http.getAccount()
}
return ( return (
<> <>
<Hero></Hero> {/* <Hero></Hero> */}
<div className="container"> <div className="container">
<Button onClick={onClick}></Button> <div>{JSON.stringify(data?.data)}</div>
<div>{error?.message}</div>
{isMutating ? 1 : 2}
<Button onClick={() => trigger()}></Button>
<Button onClick={() => aa()}>Sessions</Button>
</div> </div>
</> </>
) )
}) }

11
src/views/PlayGround.tsx

@ -1,11 +0,0 @@
import withPage from "@/base/withPage"
function PlayGround() {
return (
<>
<div>PlayGround</div>
</>
)
}
export default withPage(PlayGround)

34
src/views/Project.tsx

@ -1,34 +0,0 @@
import withPage from "@/base/withPage"
import { useHistory } from "react-router-dom"
import styled from "styled-components"
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: #bf4f74;
`
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`
export default withPage(function Project({ children }) {
const router = useHistory()
function toChild() {
router.push("/project/child")
}
return (
<>
<Wrapper>
<Title>Hello World!</Title>
</Wrapper>
<div>
<div onClick={toChild} style={{ height: "200px" }}>
vaas
</div>
{children}
</div>
</>
)
})

4
src/viewsSys/404.tsx → src/viewsSys/NoMatch.tsx

@ -1,8 +1,8 @@
import { LeftIn } from "@/effect" import { LeftIn } from "@/effect"
export default function Page404() { export default function NoMatch() {
return ( return (
<div className="h-1/1 flex" style={{display: "flex",alignItems: "center", justifyContent: "center", height: "100%"}}> <div className="h-1/1 flex" style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%" }}>
<LeftIn className="m-auto"> <LeftIn className="m-auto">
404 404
{/* <img className="p-40px" src="static/404.jpg" alt="" /> */} {/* <img className="p-40px" src="static/404.jpg" alt="" /> */}
Loading…
Cancel
Save