generated from template/vite-react-template
add paycenter
This commit is contained in:
parent
8bd517cfcb
commit
5f59158021
@ -26,12 +26,14 @@
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@kevisual/router": "0.0.10",
|
||||
"@mui/material": "^7.0.1",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"antd": "^5.24.6",
|
||||
"clsx": "^2.1.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lucide-react": "^0.487.0",
|
||||
"nanoid": "^5.1.5",
|
||||
"qrcode": "^1.5.4",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-hook-form": "^7.55.0",
|
||||
|
226
pnpm-lock.yaml
generated
226
pnpm-lock.yaml
generated
@ -23,6 +23,9 @@ importers:
|
||||
'@mui/material':
|
||||
specifier: ^7.0.1
|
||||
version: 7.0.1(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react@19.1.0))(@types/react@19.1.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
'@types/qrcode':
|
||||
specifier: ^1.5.5
|
||||
version: 1.5.5
|
||||
antd:
|
||||
specifier: ^5.24.6
|
||||
version: 5.24.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
@ -41,6 +44,9 @@ importers:
|
||||
nanoid:
|
||||
specifier: ^5.1.5
|
||||
version: 5.1.5
|
||||
qrcode:
|
||||
specifier: ^1.5.4
|
||||
version: 1.5.4
|
||||
react:
|
||||
specifier: ^19.1.0
|
||||
version: 19.1.0
|
||||
@ -926,6 +932,9 @@ packages:
|
||||
'@types/prop-types@15.7.14':
|
||||
resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==}
|
||||
|
||||
'@types/qrcode@1.5.5':
|
||||
resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==}
|
||||
|
||||
'@types/react-dom@19.1.1':
|
||||
resolution: {integrity: sha512-jFf/woGTVTjUJsl2O7hcopJ1r0upqoq/vIOoCj0yLh3RIXxWcljlpuZ+vEBRXsymD1jhfeJrlyTy/S1UW+4y1w==}
|
||||
peerDependencies:
|
||||
@ -962,6 +971,14 @@ packages:
|
||||
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
|
||||
ansi-regex@5.0.1:
|
||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ansi-styles@4.3.0:
|
||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
antd@5.24.6:
|
||||
resolution: {integrity: sha512-xIlTa/1CTbgkZsdU/dOXkYvJXb9VoiMwsaCzpKFH2zAEY3xqOfwQ57/DdG7lAdrWP7QORtSld4UA6suxzuTHXw==}
|
||||
peerDependencies:
|
||||
@ -988,12 +1005,19 @@ packages:
|
||||
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
camelcase@5.3.1:
|
||||
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
caniuse-lite@1.0.30001684:
|
||||
resolution: {integrity: sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==}
|
||||
|
||||
classnames@2.5.1:
|
||||
resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
|
||||
|
||||
cliui@6.0.0:
|
||||
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
|
||||
|
||||
clsx@1.2.1:
|
||||
resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
|
||||
engines: {node: '>=6'}
|
||||
@ -1002,6 +1026,13 @@ packages:
|
||||
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
color-convert@2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
|
||||
color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
combined-stream@1.0.8:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@ -1048,6 +1079,10 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
decamelize@1.2.0:
|
||||
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
deepmerge@4.3.1:
|
||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -1060,6 +1095,9 @@ packages:
|
||||
resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
dijkstrajs@1.0.3:
|
||||
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
|
||||
|
||||
dom-helpers@5.2.1:
|
||||
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
|
||||
|
||||
@ -1074,6 +1112,9 @@ packages:
|
||||
electron-to-chromium@1.5.65:
|
||||
resolution: {integrity: sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
enhanced-resolve@5.18.1:
|
||||
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@ -1128,6 +1169,10 @@ packages:
|
||||
find-root@1.1.0:
|
||||
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
|
||||
|
||||
find-up@4.1.0:
|
||||
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
form-data-encoder@1.7.2:
|
||||
resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
|
||||
|
||||
@ -1151,6 +1196,10 @@ packages:
|
||||
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
get-caller-file@2.0.5:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
|
||||
get-intrinsic@1.3.0:
|
||||
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -1220,6 +1269,10 @@ packages:
|
||||
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-fullwidth-code-point@3.0.0:
|
||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-module@1.0.0:
|
||||
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
|
||||
|
||||
@ -1316,6 +1369,10 @@ packages:
|
||||
lines-and-columns@1.2.4:
|
||||
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||
|
||||
locate-path@5.0.0:
|
||||
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
lodash-es@4.17.21:
|
||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
|
||||
@ -1395,6 +1452,18 @@ packages:
|
||||
zod:
|
||||
optional: true
|
||||
|
||||
p-limit@2.3.0:
|
||||
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
p-locate@4.1.0:
|
||||
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
p-try@2.2.0:
|
||||
resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
parent-module@1.0.1:
|
||||
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||
engines: {node: '>=6'}
|
||||
@ -1403,6 +1472,10 @@ packages:
|
||||
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
path-exists@4.0.0:
|
||||
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
path-parse@1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
|
||||
@ -1424,6 +1497,10 @@ packages:
|
||||
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
pngjs@5.0.0:
|
||||
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
postcss@8.5.3:
|
||||
resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
@ -1431,6 +1508,11 @@ packages:
|
||||
prop-types@15.8.1:
|
||||
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||
|
||||
qrcode@1.5.4:
|
||||
resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
|
||||
rc-cascader@3.33.1:
|
||||
resolution: {integrity: sha512-Kyl4EJ7ZfCBuidmZVieegcbFw0RcU5bHHSbtEdmuLYd0fYHCAiYKZ6zon7fWAVyC6rWWOOib0XKdTSf7ElC9rg==}
|
||||
peerDependencies:
|
||||
@ -1744,6 +1826,13 @@ packages:
|
||||
regenerator-runtime@0.14.1:
|
||||
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
|
||||
|
||||
require-directory@2.1.1:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
require-main-filename@2.0.0:
|
||||
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
|
||||
|
||||
resize-observer-polyfill@1.5.1:
|
||||
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
||||
|
||||
@ -1782,6 +1871,9 @@ packages:
|
||||
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
||||
hasBin: true
|
||||
|
||||
set-blocking@2.0.0:
|
||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||
|
||||
set-cookie-parser@2.7.1:
|
||||
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
|
||||
|
||||
@ -1796,6 +1888,14 @@ packages:
|
||||
string-convert@0.2.1:
|
||||
resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==}
|
||||
|
||||
string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
stylis@4.2.0:
|
||||
resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
|
||||
|
||||
@ -1909,6 +2009,13 @@ packages:
|
||||
whatwg-url@5.0.0:
|
||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
||||
|
||||
which-module@2.0.1:
|
||||
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ws@8.18.1:
|
||||
resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
@ -1921,6 +2028,9 @@ packages:
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
y18n@4.0.3:
|
||||
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
||||
|
||||
yallist@3.1.1:
|
||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||
|
||||
@ -1933,6 +2043,14 @@ packages:
|
||||
engines: {node: '>= 14'}
|
||||
hasBin: true
|
||||
|
||||
yargs-parser@18.1.3:
|
||||
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
yargs@15.4.1:
|
||||
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
zustand@5.0.3:
|
||||
resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
@ -2713,6 +2831,10 @@ snapshots:
|
||||
|
||||
'@types/prop-types@15.7.14': {}
|
||||
|
||||
'@types/qrcode@1.5.5':
|
||||
dependencies:
|
||||
'@types/node': 22.14.0
|
||||
|
||||
'@types/react-dom@19.1.1(@types/react@19.1.0)':
|
||||
dependencies:
|
||||
'@types/react': 19.1.0
|
||||
@ -2750,6 +2872,12 @@ snapshots:
|
||||
dependencies:
|
||||
humanize-ms: 1.2.1
|
||||
|
||||
ansi-regex@5.0.1: {}
|
||||
|
||||
ansi-styles@4.3.0:
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
|
||||
antd@5.24.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
'@ant-design/colors': 7.2.0
|
||||
@ -2830,14 +2958,28 @@ snapshots:
|
||||
|
||||
callsites@3.1.0: {}
|
||||
|
||||
camelcase@5.3.1: {}
|
||||
|
||||
caniuse-lite@1.0.30001684: {}
|
||||
|
||||
classnames@2.5.1: {}
|
||||
|
||||
cliui@6.0.0:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 6.2.0
|
||||
|
||||
clsx@1.2.1: {}
|
||||
|
||||
clsx@2.1.1: {}
|
||||
|
||||
color-convert@2.0.1:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
combined-stream@1.0.8:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
@ -2874,12 +3016,16 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
decamelize@1.2.0: {}
|
||||
|
||||
deepmerge@4.3.1: {}
|
||||
|
||||
delayed-stream@1.0.0: {}
|
||||
|
||||
detect-libc@2.0.3: {}
|
||||
|
||||
dijkstrajs@1.0.3: {}
|
||||
|
||||
dom-helpers@5.2.1:
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.0
|
||||
@ -2895,6 +3041,8 @@ snapshots:
|
||||
|
||||
electron-to-chromium@1.5.65: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
enhanced-resolve@5.18.1:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
@ -2961,6 +3109,11 @@ snapshots:
|
||||
|
||||
find-root@1.1.0: {}
|
||||
|
||||
find-up@4.1.0:
|
||||
dependencies:
|
||||
locate-path: 5.0.0
|
||||
path-exists: 4.0.0
|
||||
|
||||
form-data-encoder@1.7.2: {}
|
||||
|
||||
form-data@4.0.2:
|
||||
@ -2982,6 +3135,8 @@ snapshots:
|
||||
|
||||
gensync@1.0.0-beta.2: {}
|
||||
|
||||
get-caller-file@2.0.5: {}
|
||||
|
||||
get-intrinsic@1.3.0:
|
||||
dependencies:
|
||||
call-bind-apply-helpers: 1.0.2
|
||||
@ -3052,6 +3207,8 @@ snapshots:
|
||||
dependencies:
|
||||
hasown: 2.0.2
|
||||
|
||||
is-fullwidth-code-point@3.0.0: {}
|
||||
|
||||
is-module@1.0.0: {}
|
||||
|
||||
is-reference@1.2.1:
|
||||
@ -3119,6 +3276,10 @@ snapshots:
|
||||
|
||||
lines-and-columns@1.2.4: {}
|
||||
|
||||
locate-path@5.0.0:
|
||||
dependencies:
|
||||
p-locate: 4.1.0
|
||||
|
||||
lodash-es@4.17.21: {}
|
||||
|
||||
loose-envify@1.4.0:
|
||||
@ -3177,6 +3338,16 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
p-limit@2.3.0:
|
||||
dependencies:
|
||||
p-try: 2.2.0
|
||||
|
||||
p-locate@4.1.0:
|
||||
dependencies:
|
||||
p-limit: 2.3.0
|
||||
|
||||
p-try@2.2.0: {}
|
||||
|
||||
parent-module@1.0.1:
|
||||
dependencies:
|
||||
callsites: 3.1.0
|
||||
@ -3188,6 +3359,8 @@ snapshots:
|
||||
json-parse-even-better-errors: 2.3.1
|
||||
lines-and-columns: 1.2.4
|
||||
|
||||
path-exists@4.0.0: {}
|
||||
|
||||
path-parse@1.0.7: {}
|
||||
|
||||
path-to-regexp@8.2.0: {}
|
||||
@ -3200,6 +3373,8 @@ snapshots:
|
||||
|
||||
picomatch@4.0.2: {}
|
||||
|
||||
pngjs@5.0.0: {}
|
||||
|
||||
postcss@8.5.3:
|
||||
dependencies:
|
||||
nanoid: 3.3.8
|
||||
@ -3212,6 +3387,12 @@ snapshots:
|
||||
object-assign: 4.1.1
|
||||
react-is: 16.13.1
|
||||
|
||||
qrcode@1.5.4:
|
||||
dependencies:
|
||||
dijkstrajs: 1.0.3
|
||||
pngjs: 5.0.0
|
||||
yargs: 15.4.1
|
||||
|
||||
rc-cascader@3.33.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.27.0
|
||||
@ -3604,6 +3785,10 @@ snapshots:
|
||||
|
||||
regenerator-runtime@0.14.1: {}
|
||||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
require-main-filename@2.0.0: {}
|
||||
|
||||
resize-observer-polyfill@1.5.1: {}
|
||||
|
||||
resolve-from@4.0.0: {}
|
||||
@ -3660,6 +3845,8 @@ snapshots:
|
||||
|
||||
semver@6.3.1: {}
|
||||
|
||||
set-blocking@2.0.0: {}
|
||||
|
||||
set-cookie-parser@2.7.1: {}
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
@ -3668,6 +3855,16 @@ snapshots:
|
||||
|
||||
string-convert@0.2.1: {}
|
||||
|
||||
string-width@4.2.3:
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
is-fullwidth-code-point: 3.0.0
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
strip-ansi@6.0.1:
|
||||
dependencies:
|
||||
ansi-regex: 5.0.1
|
||||
|
||||
stylis@4.2.0: {}
|
||||
|
||||
stylis@4.3.6: {}
|
||||
@ -3730,8 +3927,18 @@ snapshots:
|
||||
tr46: 0.0.3
|
||||
webidl-conversions: 3.0.1
|
||||
|
||||
which-module@2.0.1: {}
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
ws@8.18.1: {}
|
||||
|
||||
y18n@4.0.3: {}
|
||||
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yaml@1.10.2: {}
|
||||
@ -3739,6 +3946,25 @@ snapshots:
|
||||
yaml@2.5.1:
|
||||
optional: true
|
||||
|
||||
yargs-parser@18.1.3:
|
||||
dependencies:
|
||||
camelcase: 5.3.1
|
||||
decamelize: 1.2.0
|
||||
|
||||
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
|
||||
|
||||
zustand@5.0.3(@types/react@19.1.0)(immer@10.1.1)(react@19.1.0)(use-sync-external-store@1.2.2(react@19.1.0)):
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.0
|
||||
|
1
src/constant.ts
Normal file
1
src/constant.ts
Normal file
@ -0,0 +1 @@
|
||||
import { slashedBasename } from './modules/basename';
|
@ -1 +1,2 @@
|
||||
export const basename = DEV_SERVER ? '/' : BASE_NAME;
|
||||
export const slashedBasename = basename ? `${basename}/` : '/';
|
||||
|
@ -2,6 +2,7 @@ import { basename } from '../modules/basename';
|
||||
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
|
||||
console.log('basename', basename);
|
||||
import { App as AppVip } from './vip';
|
||||
import { App as AppTrade } from './trade';
|
||||
import '@ant-design/v5-patch-for-react-19';
|
||||
|
||||
export const App = () => {
|
||||
@ -12,6 +13,7 @@ export const AppRoute = () => {
|
||||
return (
|
||||
<Router basename={basename}>
|
||||
<Routes>
|
||||
<Route path='/trade' element={<AppTrade />} />
|
||||
<Route path='*' element={<AppVip />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
|
10
src/pages/trade/index.tsx
Normal file
10
src/pages/trade/index.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import { Routes, Route } from 'react-router';
|
||||
import { List } from './pages/List';
|
||||
|
||||
export const App = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route index element={<List />} />
|
||||
</Routes>
|
||||
);
|
||||
};
|
246
src/pages/trade/pages/List.tsx
Normal file
246
src/pages/trade/pages/List.tsx
Normal file
@ -0,0 +1,246 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useTradeStore } from '../store';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { Modal, Space } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { Table, Button, Select, DatePicker, Input, Form } from 'antd';
|
||||
import { ColumnType } from 'antd/es/table/interface';
|
||||
|
||||
const defaultValues = {
|
||||
title: '',
|
||||
userId: '',
|
||||
level: 'free',
|
||||
category: 'center',
|
||||
startDate: dayjs(),
|
||||
endDate: dayjs().add(1, 'month'),
|
||||
};
|
||||
export const EditDialog = () => {
|
||||
const [form] = Form.useForm();
|
||||
const store = useTradeStore(
|
||||
useShallow((state) => ({
|
||||
formData: state.formData,
|
||||
setFormData: state.setFormData,
|
||||
showEdit: state.showEdit,
|
||||
setShowEdit: state.setShowEdit,
|
||||
updateData: state.updateData,
|
||||
})),
|
||||
);
|
||||
useEffect(() => {
|
||||
if (store.showEdit) {
|
||||
if (store.formData) {
|
||||
form.setFieldsValue({
|
||||
...store.formData,
|
||||
startDate: dayjs(store.formData.startDate),
|
||||
endDate: dayjs(store.formData.endDate),
|
||||
});
|
||||
} else {
|
||||
form.setFieldsValue(defaultValues);
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
form.setFieldsValue(defaultValues);
|
||||
};
|
||||
}, [store.formData, store.showEdit]);
|
||||
const onSubmit = async (data: any) => {
|
||||
// 将dayjs对象转换为时间字符串
|
||||
const formattedData = {
|
||||
...data,
|
||||
id: store.formData?.id,
|
||||
startDate: data.startDate ? data.startDate.format('YYYY-MM-DD') : undefined,
|
||||
endDate: data.endDate ? data.endDate.format('YYYY-MM-DD') : undefined,
|
||||
};
|
||||
const res = await store.updateData(formattedData, { refresh: true });
|
||||
if (res.code === 200) {
|
||||
store.setShowEdit(false);
|
||||
store.setFormData(undefined);
|
||||
}
|
||||
};
|
||||
const onCancel = () => {
|
||||
store.setShowEdit(false);
|
||||
store.setFormData(undefined);
|
||||
};
|
||||
const hasId = !!store.formData?.id;
|
||||
return (
|
||||
<Modal
|
||||
title={hasId ? '编辑' : '添加'}
|
||||
footer={null}
|
||||
open={store.showEdit}
|
||||
onCancel={onCancel}
|
||||
style={{
|
||||
top: 40,
|
||||
}}>
|
||||
<Form
|
||||
form={form}
|
||||
labelCol={{
|
||||
span: 6,
|
||||
}}
|
||||
wrapperCol={{
|
||||
span: 18,
|
||||
}}
|
||||
className='flex flex-col gap-4 pt-4 min-w-[400px]'
|
||||
onFinish={onSubmit}>
|
||||
<Form.Item name='id' hidden>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name='title' label='标题' rules={[{ required: true, message: '请输入标题' }]}>
|
||||
<Input placeholder='请输入标题' />
|
||||
</Form.Item>
|
||||
<Form.Item name='userId' label='用户ID' rules={[{ required: true, message: '请输入用户ID' }]}>
|
||||
<Input placeholder='请输入用户ID' />
|
||||
</Form.Item>
|
||||
<Form.Item label=' ' colon={false}>
|
||||
<Button htmlType='submit'>提交</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export const List = () => {
|
||||
const store = useTradeStore(
|
||||
useShallow((state) => ({
|
||||
list: state.list,
|
||||
pagination: state.pagination,
|
||||
init: state.init,
|
||||
setShowEdit: state.setShowEdit,
|
||||
deleteData: state.deleteData,
|
||||
setFormData: state.setFormData,
|
||||
userList: state.userList,
|
||||
getList: state.getList,
|
||||
})),
|
||||
);
|
||||
useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
const columns: ColumnType<any>[] = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: 'out_trade_no',
|
||||
dataIndex: 'out_trade_no',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: 'Subject',
|
||||
dataIndex: 'subject',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '金额',
|
||||
dataIndex: 'money',
|
||||
align: 'center',
|
||||
render: (_, record) => {
|
||||
try {
|
||||
return (record.money / 100).toFixed(2);
|
||||
} catch (error) {
|
||||
return record.money;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '支付方式',
|
||||
dataIndex: 'type',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: 'uid',
|
||||
dataIndex: 'uid',
|
||||
align: 'center',
|
||||
render: (_, record) => {
|
||||
const user = store.userList?.find?.((item) => item.id === record.uid);
|
||||
return user?.username || record.uid;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '数据',
|
||||
dataIndex: 'data',
|
||||
align: 'center',
|
||||
render: (_, record) => {
|
||||
const target = record.data?.target;
|
||||
return JSON.stringify(target);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
align: 'center',
|
||||
render: (_, record) => {
|
||||
return record.createdAt ? dayjs(record.createdAt).format('YYYY-MM-DD HH:mm:ss') : '';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
fixed: 'right',
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Button
|
||||
type='link'
|
||||
onClick={() => {
|
||||
store.setShowEdit(true);
|
||||
store.setFormData(record);
|
||||
}}>
|
||||
编辑
|
||||
</Button>
|
||||
<Button type='link' onClick={() => store.deleteData(record.id)}>
|
||||
删除
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
const [formSearch] = Form.useForm();
|
||||
const onSearch = (data: any) => {
|
||||
console.log('onSearch', data);
|
||||
store.getList(data);
|
||||
};
|
||||
return (
|
||||
<div className='w-full h-full flex flex-col gap-2 bg-gray-100 p-4'>
|
||||
<div
|
||||
className='overflow-auto scrollbar relative'
|
||||
style={{
|
||||
height: 'calc(100% - 50px)',
|
||||
overflow: 'auto',
|
||||
}}>
|
||||
<Form form={formSearch} onFinish={onSearch} layout='inline' className='sticky top-0 left-0 z-10 flex gap-2 flex-wrap'>
|
||||
{/* <Button type='primary' onClick={() => store.setShowEdit(true)}>
|
||||
添加
|
||||
</Button> */}
|
||||
<Form.Item className='w-[200px]' name='search' label='标题'>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type='primary' htmlType='submit'>
|
||||
搜索
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
<Table
|
||||
className='mt-2'
|
||||
columns={columns}
|
||||
rowKey={(record) => record.id}
|
||||
dataSource={store.list}
|
||||
pagination={{
|
||||
pageSize: store.pagination.pageSize,
|
||||
total: store.pagination.total,
|
||||
current: store.pagination.page,
|
||||
onChange: (page, pageSize) => {
|
||||
store.getList({ page, pageSize });
|
||||
console.log('onChange', page, pageSize);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<EditDialog />
|
||||
</div>
|
||||
);
|
||||
};
|
56
src/pages/trade/query.ts
Normal file
56
src/pages/trade/query.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { BaseQuery } from '@kevisual/query';
|
||||
|
||||
export class TradeQuery extends BaseQuery {
|
||||
constructor(options: { query: any }) {
|
||||
super(options);
|
||||
}
|
||||
async getList(params?: any, dataOpts?: any) {
|
||||
return this.query.post(
|
||||
{
|
||||
path: 'trade',
|
||||
key: 'list',
|
||||
...params,
|
||||
},
|
||||
dataOpts,
|
||||
);
|
||||
}
|
||||
async getDetail(id?: string, dataOpts?: any) {
|
||||
return this.query.post(
|
||||
{
|
||||
path: 'trade',
|
||||
key: 'get',
|
||||
data: { id },
|
||||
},
|
||||
dataOpts,
|
||||
);
|
||||
}
|
||||
async update(data?: any, dataOpts?: any) {
|
||||
return this.query.post(
|
||||
{
|
||||
path: 'trade',
|
||||
key: 'update',
|
||||
data,
|
||||
},
|
||||
dataOpts,
|
||||
);
|
||||
}
|
||||
async delete(id?: string, dataOpts?: any) {
|
||||
return this.query.post(
|
||||
{
|
||||
path: 'trade',
|
||||
key: 'delete',
|
||||
data: { id },
|
||||
},
|
||||
dataOpts,
|
||||
);
|
||||
}
|
||||
async getMe(dataOpts?: any) {
|
||||
return this.query.post<{ id: string }>(
|
||||
{
|
||||
path: 'user',
|
||||
key: 'me',
|
||||
},
|
||||
dataOpts,
|
||||
);
|
||||
}
|
||||
}
|
111
src/pages/trade/store.ts
Normal file
111
src/pages/trade/store.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import { create } from 'zustand';
|
||||
import { query } from '@/modules/query';
|
||||
import { TradeQuery } from './query';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
export const queryApi = new TradeQuery({ query });
|
||||
type Store = {
|
||||
list: any[];
|
||||
setList: (list: any[]) => void;
|
||||
pagination: {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
total: number;
|
||||
};
|
||||
|
||||
userList: any[];
|
||||
setPagination: (pagination: { page: number; pageSize: number; total: number }) => void;
|
||||
data: any;
|
||||
setData: (data: any) => void;
|
||||
loading: boolean;
|
||||
setLoading: (loading: boolean) => void;
|
||||
formData: any;
|
||||
setFormData: (data: any) => void;
|
||||
showEdit: boolean;
|
||||
setShowEdit: (showEdit: boolean) => void;
|
||||
getList: (params?: { page?: number; pageSize?: number; category?: string; level?: string }) => Promise<any>;
|
||||
init: () => Promise<void>;
|
||||
getData: (id: string) => Promise<any>;
|
||||
updateData: (data: any, opts?: { refresh?: boolean }) => Promise<any>;
|
||||
deleteData: (id: string, opts?: { refresh?: boolean }) => Promise<any>;
|
||||
};
|
||||
export const useTradeStore = create<Store>((set, get) => ({
|
||||
list: [],
|
||||
setList: (list) => set({ list }),
|
||||
userList: [],
|
||||
pagination: {
|
||||
page: 1,
|
||||
pageSize: 2,
|
||||
total: 0,
|
||||
},
|
||||
setPagination: (pagination) => set({ pagination }),
|
||||
data: null,
|
||||
setData: (data) => set({ data }),
|
||||
loading: false,
|
||||
setLoading: (loading) => set({ loading }),
|
||||
formData: null,
|
||||
setFormData: (formData) => set({ formData }),
|
||||
showEdit: false,
|
||||
setShowEdit: (showEdit) => set({ showEdit }),
|
||||
getList: async (params?: any) => {
|
||||
set({ loading: true });
|
||||
let { page, pageSize, ...rest } = params || {};
|
||||
const res = await queryApi.getList({
|
||||
page: page || 1,
|
||||
pageSize: pageSize || 10,
|
||||
...rest,
|
||||
});
|
||||
set({ loading: false });
|
||||
if (res.code === 200) {
|
||||
set({
|
||||
list: res.data.list,
|
||||
userList: res.data.userList || [],
|
||||
pagination: res.data.pagination,
|
||||
});
|
||||
}
|
||||
return res;
|
||||
},
|
||||
init: async () => {
|
||||
await get().getList();
|
||||
},
|
||||
getData: async (id) => {
|
||||
set({ loading: true });
|
||||
const res = await queryApi.getDetail(id);
|
||||
set({ loading: false });
|
||||
if (res.code === 200) {
|
||||
const data = res.data;
|
||||
set({ data });
|
||||
}
|
||||
return res;
|
||||
},
|
||||
updateData: async (data, opts = { refresh: true }) => {
|
||||
set({ loading: true });
|
||||
const res = await queryApi.update(data);
|
||||
set({ loading: false });
|
||||
if (res.code === 200) {
|
||||
set({ data: res.data });
|
||||
toast.success('更新成功');
|
||||
} else {
|
||||
toast.error(res.message || '更新失败');
|
||||
}
|
||||
if (opts.refresh) {
|
||||
await get().getList();
|
||||
}
|
||||
return res;
|
||||
},
|
||||
deleteData: async (id, opts = { refresh: true }) => {
|
||||
set({ loading: true });
|
||||
const res = await queryApi.delete(id);
|
||||
set({ loading: false });
|
||||
if (res.code === 200) {
|
||||
set({ data: null });
|
||||
toast.success('删除成功');
|
||||
} else {
|
||||
toast.error(res.message || '删除失败');
|
||||
}
|
||||
if (opts.refresh) {
|
||||
await get().getList();
|
||||
}
|
||||
return res;
|
||||
},
|
||||
}));
|
@ -6,7 +6,7 @@ export const vipFeatureList = [
|
||||
description: '满足简单的部署应用需求',
|
||||
features: [
|
||||
{
|
||||
title: '部署10个以内的前端应用',
|
||||
title: '部署20个以内的前端应用',
|
||||
description: '可以部署10个以内的应用,包括网页应用、小程序、H5等',
|
||||
},
|
||||
{
|
||||
@ -24,7 +24,7 @@ export const vipFeatureList = [
|
||||
description: '支持一下',
|
||||
features: [
|
||||
{
|
||||
title: '部署30个以内的前端应用',
|
||||
title: '部署50个以内的前端应用',
|
||||
description: '可以部署30个以内的应用,包括网页应用、小程序、H5等',
|
||||
},
|
||||
{
|
||||
|
@ -15,6 +15,7 @@ interface VipStore {
|
||||
endDate: string;
|
||||
category: string;
|
||||
};
|
||||
user?: { id: string; [key: string]: any };
|
||||
setVipInfo: (vipInfo: any) => void;
|
||||
}
|
||||
|
||||
@ -45,7 +46,7 @@ export const VipInfo = () => {
|
||||
const store = useVipStore();
|
||||
const payModalStore = usePayModalStore(
|
||||
useShallow((state) => {
|
||||
return { setOpen: state.setOpen, setMoney: state.setMoney };
|
||||
return { setOpen: state.setOpen, setMoney: state.setMoney, setLevel: state.setLevel };
|
||||
}),
|
||||
);
|
||||
useEffect(() => {
|
||||
@ -93,13 +94,16 @@ export const VipInfo = () => {
|
||||
window.location.href = '/root/center/';
|
||||
return;
|
||||
}
|
||||
if (clickLevelNumber <= currentLevelNumber) {
|
||||
toast.info('您已经是该会员等级');
|
||||
return;
|
||||
if (clickLevelNumber < currentLevelNumber) {
|
||||
toast.info('您当前会员等级为' + currentLevel + ',无法降级, 会直接覆盖。需要修改请联系管理员。');
|
||||
} else if (clickLevelNumber === currentLevelNumber) {
|
||||
} else if (clickLevelNumber > currentLevelNumber) {
|
||||
toast.info('您当前会员等级为' + currentLevel + ',会直接覆盖原有会员等级。并重新计算会员时间。');
|
||||
}
|
||||
// 打开支付弹窗
|
||||
payModalStore.setOpen(true);
|
||||
payModalStore.setMoney(clickLevelNumber);
|
||||
payModalStore.setLevel(clickLevel);
|
||||
return;
|
||||
};
|
||||
return (
|
||||
|
@ -1,29 +1,85 @@
|
||||
import { Modal } from 'antd';
|
||||
import { create } from 'zustand';
|
||||
import { generateQRCode } from '../../../uitls/qrcode';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { queryApi } from '../store';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
interface PayModalStore {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
money: number;
|
||||
setMoney: (money: number) => void;
|
||||
level: string;
|
||||
setLevel: (level: string) => void;
|
||||
}
|
||||
export const usePayModalStore = create<PayModalStore>((set) => ({
|
||||
open: false,
|
||||
setOpen: (open: boolean) => set({ open }),
|
||||
money: 0,
|
||||
setMoney: (money: number) => set({ money }),
|
||||
level: 'money',
|
||||
setLevel: (level: string) => set({ level }),
|
||||
}));
|
||||
|
||||
export const PayModal = () => {
|
||||
const { open, setOpen, money } = usePayModalStore();
|
||||
const { open, setOpen, money, level } = usePayModalStore();
|
||||
const [wxQrCode, setWxQrCode] = useState('');
|
||||
const [wxIframeURL, setWxIframeURL] = useState('');
|
||||
const [alipayIframeURL, setAlipayIframeURL] = useState('');
|
||||
const [payMode, setPayMode] = useState<'wx' | 'alipay' | 'unset'>('unset');
|
||||
useEffect(() => {
|
||||
initQrCode(wxIframeURL);
|
||||
}, [wxIframeURL]);
|
||||
const initQrCode = async (url: string) => {
|
||||
if (!url) return;
|
||||
const wxQrCode = await generateQRCode(url);
|
||||
setWxQrCode(wxQrCode);
|
||||
};
|
||||
const onPay = async (payMode: 'wx' | 'alipay') => {
|
||||
const res = await queryApi.vipPay({
|
||||
level,
|
||||
money: money * 100,
|
||||
payMode,
|
||||
});
|
||||
if (res.code === 200) {
|
||||
if (payMode === 'wx') {
|
||||
const form = res.data.url;
|
||||
const wxQrCode = await generateQRCode(form);
|
||||
setWxQrCode(wxQrCode);
|
||||
} else {
|
||||
const form = res.data.form;
|
||||
setAlipayIframeURL(form);
|
||||
}
|
||||
} else {
|
||||
toast.error(res.message || '支付失败');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal open={open} onCancel={() => setOpen(false)} maskClosable={false} footer={null}>
|
||||
<div className='px-4 py-4 flex flex-col gap-4 select-none'>
|
||||
<Modal open={open} onCancel={() => setOpen(false)} maskClosable={false} footer={null} style={{}}>
|
||||
<div className='px-4 py-4 flex flex-col gap-4 select-none justify-center items-center'>
|
||||
<h2 className='text-2xl font-bold mb-4'>支付确认</h2>
|
||||
<p className='text-lg'>请确认支付金额:{money} 元</p>
|
||||
{payMode === 'wx' && wxQrCode && <img className='w-[210px] h-[210px] ' src={wxQrCode} alt='微信支付' />}
|
||||
{payMode === 'alipay' && alipayIframeURL && <iframe src={alipayIframeURL} className='w-[210px] h-[210px]' />}
|
||||
<div className='flex gap-2'>
|
||||
<button className='bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 cursor-pointer'>微信支付</button>
|
||||
<button className='bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 cursor-pointer'>支付宝支付</button>
|
||||
<button
|
||||
className='bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 cursor-pointer'
|
||||
onClick={() => {
|
||||
setPayMode('wx');
|
||||
onPay('wx');
|
||||
}}>
|
||||
微信支付
|
||||
</button>
|
||||
<button
|
||||
className='bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 cursor-pointer'
|
||||
onClick={() => {
|
||||
setPayMode('alipay');
|
||||
onPay('alipay');
|
||||
}}>
|
||||
支付宝支付
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
@ -21,7 +21,7 @@ export const VipCategory = [
|
||||
},
|
||||
{
|
||||
label: 'AI Chat',
|
||||
value: 'chat',
|
||||
value: 'ai-chat',
|
||||
},
|
||||
];
|
||||
export class QueryApi extends BaseQuery {
|
||||
@ -98,4 +98,23 @@ export class QueryApi extends BaseQuery {
|
||||
dataOpts,
|
||||
);
|
||||
}
|
||||
async vipPay(
|
||||
data?: {
|
||||
level: string;
|
||||
payMode?: string;
|
||||
out_trade_no?: string;
|
||||
month?: number;
|
||||
money: number;
|
||||
},
|
||||
dataOpts?: any,
|
||||
) {
|
||||
return this.query.post(
|
||||
{
|
||||
path: 'vip',
|
||||
key: 'pay',
|
||||
data,
|
||||
},
|
||||
dataOpts,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
6
src/uitls/qrcode.ts
Normal file
6
src/uitls/qrcode.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import QRCode from 'qrcode';
|
||||
|
||||
export const generateQRCode = async (url: string) => {
|
||||
const qrCode = await QRCode.toDataURL(url);
|
||||
return qrCode;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user