generated from template/vite-react-template
	add paycenter
This commit is contained in:
		@@ -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;
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user