This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "saas2",
|
"name": "saas3",
|
||||||
"version": "0.1.0",
|
"version": "3.6.12",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
"@ant-design/icons": "^6.0.0",
|
"@ant-design/icons": "^6.0.0",
|
||||||
"@ant-design/pro-components": "^2.8.7",
|
"@ant-design/pro-components": "^2.8.7",
|
||||||
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
||||||
|
"@emotion/css": "^11.13.5",
|
||||||
"@iconify/react": "^4.1.1",
|
"@iconify/react": "^4.1.1",
|
||||||
"@types/lodash": "^4.17.17",
|
"@types/lodash": "^4.17.17",
|
||||||
"antd": "^5.25.4",
|
"antd": "^5.25.4",
|
||||||
@@ -46,6 +47,7 @@
|
|||||||
"zustand": "^5.0.5"
|
"zustand": "^5.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@next/bundle-analyzer": "^15.3.3",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/jsonwebtoken": "^9.0.9",
|
"@types/jsonwebtoken": "^9.0.9",
|
||||||
|
|||||||
500
pnpm-lock.yaml
generated
500
pnpm-lock.yaml
generated
@@ -20,6 +20,9 @@ importers:
|
|||||||
'@ant-design/v5-patch-for-react-19':
|
'@ant-design/v5-patch-for-react-19':
|
||||||
specifier: ^1.0.3
|
specifier: ^1.0.3
|
||||||
version: 1.0.3(antd@5.25.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 1.0.3(antd@5.25.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
'@emotion/css':
|
||||||
|
specifier: ^11.13.5
|
||||||
|
version: 11.13.5
|
||||||
'@iconify/react':
|
'@iconify/react':
|
||||||
specifier: ^4.1.1
|
specifier: ^4.1.1
|
||||||
version: 4.1.1(react@19.1.0)
|
version: 4.1.1(react@19.1.0)
|
||||||
@@ -114,6 +117,9 @@ importers:
|
|||||||
specifier: ^5.0.5
|
specifier: ^5.0.5
|
||||||
version: 5.0.5(@types/react@19.1.6)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0))
|
version: 5.0.5(@types/react@19.1.6)(react@19.1.0)(use-sync-external-store@1.5.0(react@19.1.0))
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@next/bundle-analyzer':
|
||||||
|
specifier: ^15.3.3
|
||||||
|
version: 15.3.3
|
||||||
'@tailwindcss/postcss':
|
'@tailwindcss/postcss':
|
||||||
specifier: ^4
|
specifier: ^4
|
||||||
version: 4.1.8
|
version: 4.1.8
|
||||||
@@ -290,10 +296,47 @@ packages:
|
|||||||
react: '>=19.0.0'
|
react: '>=19.0.0'
|
||||||
react-dom: '>=19.0.0'
|
react-dom: '>=19.0.0'
|
||||||
|
|
||||||
|
'@babel/code-frame@7.27.1':
|
||||||
|
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/generator@7.27.5':
|
||||||
|
resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/helper-module-imports@7.27.1':
|
||||||
|
resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/helper-string-parser@7.27.1':
|
||||||
|
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/helper-validator-identifier@7.27.1':
|
||||||
|
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/parser@7.27.5':
|
||||||
|
resolution: {integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
'@babel/runtime@7.27.4':
|
'@babel/runtime@7.27.4':
|
||||||
resolution: {integrity: sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==}
|
resolution: {integrity: sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/template@7.27.2':
|
||||||
|
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/traverse@7.27.4':
|
||||||
|
resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
|
'@babel/types@7.27.6':
|
||||||
|
resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
|
||||||
'@chenshuai2144/sketch-color@1.0.9':
|
'@chenshuai2144/sketch-color@1.0.9':
|
||||||
resolution: {integrity: sha512-obzSy26cb7Pm7OprWyVpgMpIlrZpZ0B7vbrU0RMbvRg0YAI890S5Xy02Aj1Nhl4+KTbi1lVYHt6HQP8Hm9s+1w==}
|
resolution: {integrity: sha512-obzSy26cb7Pm7OprWyVpgMpIlrZpZ0B7vbrU0RMbvRg0YAI890S5Xy02Aj1Nhl4+KTbi1lVYHt6HQP8Hm9s+1w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -303,6 +346,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==}
|
resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
'@discoveryjs/json-ext@0.5.7':
|
||||||
|
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
'@dnd-kit/accessibility@3.1.1':
|
'@dnd-kit/accessibility@3.1.1':
|
||||||
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
|
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -334,21 +381,51 @@ packages:
|
|||||||
'@emnapi/runtime@1.4.3':
|
'@emnapi/runtime@1.4.3':
|
||||||
resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==}
|
resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==}
|
||||||
|
|
||||||
|
'@emotion/babel-plugin@11.13.5':
|
||||||
|
resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==}
|
||||||
|
|
||||||
|
'@emotion/cache@11.14.0':
|
||||||
|
resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==}
|
||||||
|
|
||||||
|
'@emotion/css@11.13.5':
|
||||||
|
resolution: {integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==}
|
||||||
|
|
||||||
'@emotion/hash@0.8.0':
|
'@emotion/hash@0.8.0':
|
||||||
resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
|
resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
|
||||||
|
|
||||||
|
'@emotion/hash@0.9.2':
|
||||||
|
resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==}
|
||||||
|
|
||||||
'@emotion/is-prop-valid@1.2.2':
|
'@emotion/is-prop-valid@1.2.2':
|
||||||
resolution: {integrity: sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==}
|
resolution: {integrity: sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==}
|
||||||
|
|
||||||
'@emotion/memoize@0.8.1':
|
'@emotion/memoize@0.8.1':
|
||||||
resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==}
|
resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==}
|
||||||
|
|
||||||
|
'@emotion/memoize@0.9.0':
|
||||||
|
resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
|
||||||
|
|
||||||
|
'@emotion/serialize@1.3.3':
|
||||||
|
resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==}
|
||||||
|
|
||||||
|
'@emotion/sheet@1.4.0':
|
||||||
|
resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==}
|
||||||
|
|
||||||
|
'@emotion/unitless@0.10.0':
|
||||||
|
resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==}
|
||||||
|
|
||||||
'@emotion/unitless@0.7.5':
|
'@emotion/unitless@0.7.5':
|
||||||
resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==}
|
resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==}
|
||||||
|
|
||||||
'@emotion/unitless@0.8.1':
|
'@emotion/unitless@0.8.1':
|
||||||
resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==}
|
resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==}
|
||||||
|
|
||||||
|
'@emotion/utils@1.4.2':
|
||||||
|
resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==}
|
||||||
|
|
||||||
|
'@emotion/weak-memoize@0.4.0':
|
||||||
|
resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==}
|
||||||
|
|
||||||
'@iconify/react@4.1.1':
|
'@iconify/react@4.1.1':
|
||||||
resolution: {integrity: sha512-jed14EjvKjee8mc0eoscGxlg7mSQRkwQG3iX3cPBCO7UlOjz0DtlvTqxqEcHUJGh+z1VJ31Yhu5B9PxfO0zbdg==}
|
resolution: {integrity: sha512-jed14EjvKjee8mc0eoscGxlg7mSQRkwQG3iX3cPBCO7UlOjz0DtlvTqxqEcHUJGh+z1VJ31Yhu5B9PxfO0zbdg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -498,6 +575,9 @@ packages:
|
|||||||
'@mongodb-js/saslprep@1.2.2':
|
'@mongodb-js/saslprep@1.2.2':
|
||||||
resolution: {integrity: sha512-EB0O3SCSNRUFk66iRCpI+cXzIjdswfCs7F6nOC3RAGJ7xr5YhaicvsRwJ9eyzYvYRlCSDUO/c7g4yNulxKC1WA==}
|
resolution: {integrity: sha512-EB0O3SCSNRUFk66iRCpI+cXzIjdswfCs7F6nOC3RAGJ7xr5YhaicvsRwJ9eyzYvYRlCSDUO/c7g4yNulxKC1WA==}
|
||||||
|
|
||||||
|
'@next/bundle-analyzer@15.3.3':
|
||||||
|
resolution: {integrity: sha512-9gddnjACK6yOa5IkmeFyzcwZh2rscsb6ZspTd7tymPYKQM96fJuKjn9HrRtPNKiMm7ExKNadAJqREmHdBgHZ9A==}
|
||||||
|
|
||||||
'@next/env@15.3.3':
|
'@next/env@15.3.3':
|
||||||
resolution: {integrity: sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==}
|
resolution: {integrity: sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==}
|
||||||
|
|
||||||
@@ -549,6 +629,9 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@polka/url@1.0.0-next.29':
|
||||||
|
resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==}
|
||||||
|
|
||||||
'@rc-component/async-validator@5.0.4':
|
'@rc-component/async-validator@5.0.4':
|
||||||
resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==}
|
resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==}
|
||||||
engines: {node: '>=14.x'}
|
engines: {node: '>=14.x'}
|
||||||
@@ -765,6 +848,9 @@ packages:
|
|||||||
'@types/node@20.17.57':
|
'@types/node@20.17.57':
|
||||||
resolution: {integrity: sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==}
|
resolution: {integrity: sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ==}
|
||||||
|
|
||||||
|
'@types/parse-json@4.0.2':
|
||||||
|
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||||
|
|
||||||
'@types/ramda@0.30.2':
|
'@types/ramda@0.30.2':
|
||||||
resolution: {integrity: sha512-PyzHvjCalm2BRYjAU6nIB3TprYwMNOUY/7P/N8bSzp9W/yM2YrtGtAnnVtaCNSeOZ8DzKyFDvaqQs7LnWwwmBA==}
|
resolution: {integrity: sha512-PyzHvjCalm2BRYjAU6nIB3TprYwMNOUY/7P/N8bSzp9W/yM2YrtGtAnnVtaCNSeOZ8DzKyFDvaqQs7LnWwwmBA==}
|
||||||
|
|
||||||
@@ -816,6 +902,15 @@ packages:
|
|||||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
acorn-walk@8.3.4:
|
||||||
|
resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
|
acorn@8.15.0:
|
||||||
|
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
add-dom-event-listener@1.1.0:
|
add-dom-event-listener@1.1.0:
|
||||||
resolution: {integrity: sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==}
|
resolution: {integrity: sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==}
|
||||||
|
|
||||||
@@ -832,6 +927,10 @@ packages:
|
|||||||
apexcharts@4.7.0:
|
apexcharts@4.7.0:
|
||||||
resolution: {integrity: sha512-iZSrrBGvVlL+nt2B1NpqfDuBZ9jX61X9I2+XV0hlYXHtTwhwLTHDKGXjNXAgFBDLuvSYCB/rq2nPWVPRv2DrGA==}
|
resolution: {integrity: sha512-iZSrrBGvVlL+nt2B1NpqfDuBZ9jX61X9I2+XV0hlYXHtTwhwLTHDKGXjNXAgFBDLuvSYCB/rq2nPWVPRv2DrGA==}
|
||||||
|
|
||||||
|
babel-plugin-macros@3.1.0:
|
||||||
|
resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
|
||||||
|
engines: {node: '>=10', npm: '>=6'}
|
||||||
|
|
||||||
bail@2.0.2:
|
bail@2.0.2:
|
||||||
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
|
resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==}
|
||||||
|
|
||||||
@@ -854,6 +953,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
|
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
|
||||||
engines: {node: '>=10.16.0'}
|
engines: {node: '>=10.16.0'}
|
||||||
|
|
||||||
|
callsites@3.1.0:
|
||||||
|
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
camelize@1.0.1:
|
camelize@1.0.1:
|
||||||
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
|
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
|
||||||
|
|
||||||
@@ -926,9 +1029,16 @@ packages:
|
|||||||
comma-separated-tokens@2.0.3:
|
comma-separated-tokens@2.0.3:
|
||||||
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
|
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
|
||||||
|
|
||||||
|
commander@7.2.0:
|
||||||
|
resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
|
||||||
compute-scroll-into-view@3.1.1:
|
compute-scroll-into-view@3.1.1:
|
||||||
resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
|
resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==}
|
||||||
|
|
||||||
|
convert-source-map@1.9.0:
|
||||||
|
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
|
||||||
|
|
||||||
cookie@0.7.2:
|
cookie@0.7.2:
|
||||||
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -940,6 +1050,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
|
cosmiconfig@7.1.0:
|
||||||
|
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
crc-32@1.2.2:
|
crc-32@1.2.2:
|
||||||
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
|
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
@@ -958,6 +1072,9 @@ packages:
|
|||||||
dayjs@1.11.13:
|
dayjs@1.11.13:
|
||||||
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
|
||||||
|
|
||||||
|
debounce@1.2.1:
|
||||||
|
resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==}
|
||||||
|
|
||||||
debug@4.3.7:
|
debug@4.3.7:
|
||||||
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
|
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
|
||||||
engines: {node: '>=6.0'}
|
engines: {node: '>=6.0'}
|
||||||
@@ -990,6 +1107,9 @@ packages:
|
|||||||
devlop@1.1.0:
|
devlop@1.1.0:
|
||||||
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
|
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
|
||||||
|
|
||||||
|
duplexer@0.1.2:
|
||||||
|
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
|
||||||
|
|
||||||
ecdsa-sig-formatter@1.0.11:
|
ecdsa-sig-formatter@1.0.11:
|
||||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||||
|
|
||||||
@@ -1021,6 +1141,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
|
||||||
engines: {node: '>=0.12'}
|
engines: {node: '>=0.12'}
|
||||||
|
|
||||||
|
error-ex@1.3.2:
|
||||||
|
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||||
|
|
||||||
|
escape-string-regexp@4.0.0:
|
||||||
|
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
escape-string-regexp@5.0.0:
|
escape-string-regexp@5.0.0:
|
||||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -1037,18 +1164,36 @@ packages:
|
|||||||
file-saver@2.0.5:
|
file-saver@2.0.5:
|
||||||
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
|
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
|
||||||
|
|
||||||
|
find-root@1.1.0:
|
||||||
|
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
|
||||||
|
|
||||||
frac@1.1.2:
|
frac@1.1.2:
|
||||||
resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
|
resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
function-bind@1.1.2:
|
||||||
|
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||||
|
|
||||||
geist@1.4.2:
|
geist@1.4.2:
|
||||||
resolution: {integrity: sha512-OQUga/KUc8ueijck6EbtT07L4tZ5+TZgjw8PyWfxo16sL5FWk7gNViPNU8hgCFjy6bJi9yuTP+CRpywzaGN8zw==}
|
resolution: {integrity: sha512-OQUga/KUc8ueijck6EbtT07L4tZ5+TZgjw8PyWfxo16sL5FWk7gNViPNU8hgCFjy6bJi9yuTP+CRpywzaGN8zw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
next: '>=13.2.0'
|
next: '>=13.2.0'
|
||||||
|
|
||||||
|
globals@11.12.0:
|
||||||
|
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
graceful-fs@4.2.11:
|
graceful-fs@4.2.11:
|
||||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||||
|
|
||||||
|
gzip-size@6.0.0:
|
||||||
|
resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
hasown@2.0.2:
|
||||||
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
hast-util-from-parse5@8.0.3:
|
hast-util-from-parse5@8.0.3:
|
||||||
resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
|
resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==}
|
||||||
|
|
||||||
@@ -1080,12 +1225,19 @@ packages:
|
|||||||
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
|
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
|
html-escaper@2.0.2:
|
||||||
|
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
||||||
|
|
||||||
html-url-attributes@3.0.1:
|
html-url-attributes@3.0.1:
|
||||||
resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==}
|
resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==}
|
||||||
|
|
||||||
html-void-elements@3.0.0:
|
html-void-elements@3.0.0:
|
||||||
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==}
|
||||||
|
|
||||||
|
import-fresh@3.3.1:
|
||||||
|
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
inline-style-parser@0.2.4:
|
inline-style-parser@0.2.4:
|
||||||
resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
|
resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
|
||||||
|
|
||||||
@@ -1095,9 +1247,16 @@ packages:
|
|||||||
is-alphanumerical@2.0.1:
|
is-alphanumerical@2.0.1:
|
||||||
resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==}
|
resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==}
|
||||||
|
|
||||||
|
is-arrayish@0.2.1:
|
||||||
|
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
||||||
|
|
||||||
is-arrayish@0.3.2:
|
is-arrayish@0.3.2:
|
||||||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||||
|
|
||||||
|
is-core-module@2.16.1:
|
||||||
|
resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
is-decimal@2.0.1:
|
is-decimal@2.0.1:
|
||||||
resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
|
resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
|
||||||
|
|
||||||
@@ -1108,6 +1267,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
|
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
is-plain-object@5.0.0:
|
||||||
|
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
jiti@2.4.2:
|
jiti@2.4.2:
|
||||||
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
|
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -1115,6 +1278,14 @@ packages:
|
|||||||
js-tokens@4.0.0:
|
js-tokens@4.0.0:
|
||||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||||
|
|
||||||
|
jsesc@3.1.0:
|
||||||
|
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
json-parse-even-better-errors@2.3.1:
|
||||||
|
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
|
||||||
|
|
||||||
json2mq@0.2.0:
|
json2mq@0.2.0:
|
||||||
resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==}
|
resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==}
|
||||||
|
|
||||||
@@ -1196,6 +1367,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
|
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
|
|
||||||
|
lines-and-columns@1.2.4:
|
||||||
|
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
|
||||||
|
|
||||||
lodash-es@4.17.21:
|
lodash-es@4.17.21:
|
||||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||||
|
|
||||||
@@ -1434,6 +1608,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==}
|
resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
|
|
||||||
|
mrmime@2.0.1:
|
||||||
|
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
@@ -1471,16 +1649,35 @@ packages:
|
|||||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
opener@1.5.2:
|
||||||
|
resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
parent-module@1.0.1:
|
||||||
|
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
parse-entities@4.0.2:
|
parse-entities@4.0.2:
|
||||||
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
|
resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==}
|
||||||
|
|
||||||
|
parse-json@5.2.0:
|
||||||
|
resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
parse5@7.3.0:
|
parse5@7.3.0:
|
||||||
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
|
resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==}
|
||||||
|
|
||||||
|
path-parse@1.0.7:
|
||||||
|
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||||
|
|
||||||
path-to-regexp@8.2.0:
|
path-to-regexp@8.2.0:
|
||||||
resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
|
resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
|
path-type@4.0.0:
|
||||||
|
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
picocolors@1.1.1:
|
picocolors@1.1.1:
|
||||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
@@ -1818,6 +2015,15 @@ packages:
|
|||||||
resize-observer-polyfill@1.5.1:
|
resize-observer-polyfill@1.5.1:
|
||||||
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
||||||
|
|
||||||
|
resolve-from@4.0.0:
|
||||||
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
resolve@1.22.10:
|
||||||
|
resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
safe-buffer@5.2.1:
|
safe-buffer@5.2.1:
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||||
|
|
||||||
@@ -1849,6 +2055,10 @@ packages:
|
|||||||
simple-swizzle@0.2.2:
|
simple-swizzle@0.2.2:
|
||||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||||
|
|
||||||
|
sirv@2.0.4:
|
||||||
|
resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
|
||||||
size-sensor@1.0.2:
|
size-sensor@1.0.2:
|
||||||
resolution: {integrity: sha512-2NCmWxY7A9pYKGXNBfteo4hy14gWu47rg5692peVMst6lQLPKrVjhY+UTEsPI5ceFRJSl3gVgMYaUi/hKuaiKw==}
|
resolution: {integrity: sha512-2NCmWxY7A9pYKGXNBfteo4hy14gWu47rg5692peVMst6lQLPKrVjhY+UTEsPI5ceFRJSl3gVgMYaUi/hKuaiKw==}
|
||||||
|
|
||||||
@@ -1871,6 +2081,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
source-map@0.5.7:
|
||||||
|
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
space-separated-tokens@2.0.2:
|
space-separated-tokens@2.0.2:
|
||||||
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
||||||
|
|
||||||
@@ -1917,12 +2131,19 @@ packages:
|
|||||||
babel-plugin-macros:
|
babel-plugin-macros:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
stylis@4.2.0:
|
||||||
|
resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
|
||||||
|
|
||||||
stylis@4.3.2:
|
stylis@4.3.2:
|
||||||
resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==}
|
resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==}
|
||||||
|
|
||||||
stylis@4.3.6:
|
stylis@4.3.6:
|
||||||
resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==}
|
resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==}
|
||||||
|
|
||||||
|
supports-preserve-symlinks-flag@1.0.0:
|
||||||
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
swr@2.3.3:
|
swr@2.3.3:
|
||||||
resolution: {integrity: sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==}
|
resolution: {integrity: sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1949,6 +2170,10 @@ packages:
|
|||||||
toggle-selection@1.0.6:
|
toggle-selection@1.0.6:
|
||||||
resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==}
|
resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==}
|
||||||
|
|
||||||
|
totalist@3.0.1:
|
||||||
|
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
tr46@5.1.1:
|
tr46@5.1.1:
|
||||||
resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
|
resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -2035,6 +2260,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
webpack-bundle-analyzer@4.10.1:
|
||||||
|
resolution: {integrity: sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==}
|
||||||
|
engines: {node: '>= 10.13.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
whatwg-url@14.2.0:
|
whatwg-url@14.2.0:
|
||||||
resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
|
resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -2047,6 +2277,18 @@ packages:
|
|||||||
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
|
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
ws@7.5.10:
|
||||||
|
resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==}
|
||||||
|
engines: {node: '>=8.3.0'}
|
||||||
|
peerDependencies:
|
||||||
|
bufferutil: ^4.0.1
|
||||||
|
utf-8-validate: ^5.0.2
|
||||||
|
peerDependenciesMeta:
|
||||||
|
bufferutil:
|
||||||
|
optional: true
|
||||||
|
utf-8-validate:
|
||||||
|
optional: true
|
||||||
|
|
||||||
ws@8.17.1:
|
ws@8.17.1:
|
||||||
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
@@ -2072,6 +2314,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
|
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
yaml@1.10.2:
|
||||||
|
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
zrender@5.6.1:
|
zrender@5.6.1:
|
||||||
resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==}
|
resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==}
|
||||||
|
|
||||||
@@ -2363,8 +2609,60 @@ snapshots:
|
|||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-dom: 19.1.0(react@19.1.0)
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
|
||||||
|
'@babel/code-frame@7.27.1':
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
|
js-tokens: 4.0.0
|
||||||
|
picocolors: 1.1.1
|
||||||
|
|
||||||
|
'@babel/generator@7.27.5':
|
||||||
|
dependencies:
|
||||||
|
'@babel/parser': 7.27.5
|
||||||
|
'@babel/types': 7.27.6
|
||||||
|
'@jridgewell/gen-mapping': 0.3.8
|
||||||
|
'@jridgewell/trace-mapping': 0.3.25
|
||||||
|
jsesc: 3.1.0
|
||||||
|
|
||||||
|
'@babel/helper-module-imports@7.27.1':
|
||||||
|
dependencies:
|
||||||
|
'@babel/traverse': 7.27.4
|
||||||
|
'@babel/types': 7.27.6
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@babel/helper-string-parser@7.27.1': {}
|
||||||
|
|
||||||
|
'@babel/helper-validator-identifier@7.27.1': {}
|
||||||
|
|
||||||
|
'@babel/parser@7.27.5':
|
||||||
|
dependencies:
|
||||||
|
'@babel/types': 7.27.6
|
||||||
|
|
||||||
'@babel/runtime@7.27.4': {}
|
'@babel/runtime@7.27.4': {}
|
||||||
|
|
||||||
|
'@babel/template@7.27.2':
|
||||||
|
dependencies:
|
||||||
|
'@babel/code-frame': 7.27.1
|
||||||
|
'@babel/parser': 7.27.5
|
||||||
|
'@babel/types': 7.27.6
|
||||||
|
|
||||||
|
'@babel/traverse@7.27.4':
|
||||||
|
dependencies:
|
||||||
|
'@babel/code-frame': 7.27.1
|
||||||
|
'@babel/generator': 7.27.5
|
||||||
|
'@babel/parser': 7.27.5
|
||||||
|
'@babel/template': 7.27.2
|
||||||
|
'@babel/types': 7.27.6
|
||||||
|
debug: 4.4.1
|
||||||
|
globals: 11.12.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@babel/types@7.27.6':
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-string-parser': 7.27.1
|
||||||
|
'@babel/helper-validator-identifier': 7.27.1
|
||||||
|
|
||||||
'@chenshuai2144/sketch-color@1.0.9(react@19.1.0)':
|
'@chenshuai2144/sketch-color@1.0.9(react@19.1.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
@@ -2373,6 +2671,8 @@ snapshots:
|
|||||||
|
|
||||||
'@ctrl/tinycolor@3.6.1': {}
|
'@ctrl/tinycolor@3.6.1': {}
|
||||||
|
|
||||||
|
'@discoveryjs/json-ext@0.5.7': {}
|
||||||
|
|
||||||
'@dnd-kit/accessibility@3.1.1(react@19.1.0)':
|
'@dnd-kit/accessibility@3.1.1(react@19.1.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
@@ -2410,18 +2710,72 @@ snapshots:
|
|||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@emotion/babel-plugin@11.13.5':
|
||||||
|
dependencies:
|
||||||
|
'@babel/helper-module-imports': 7.27.1
|
||||||
|
'@babel/runtime': 7.27.4
|
||||||
|
'@emotion/hash': 0.9.2
|
||||||
|
'@emotion/memoize': 0.9.0
|
||||||
|
'@emotion/serialize': 1.3.3
|
||||||
|
babel-plugin-macros: 3.1.0
|
||||||
|
convert-source-map: 1.9.0
|
||||||
|
escape-string-regexp: 4.0.0
|
||||||
|
find-root: 1.1.0
|
||||||
|
source-map: 0.5.7
|
||||||
|
stylis: 4.2.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@emotion/cache@11.14.0':
|
||||||
|
dependencies:
|
||||||
|
'@emotion/memoize': 0.9.0
|
||||||
|
'@emotion/sheet': 1.4.0
|
||||||
|
'@emotion/utils': 1.4.2
|
||||||
|
'@emotion/weak-memoize': 0.4.0
|
||||||
|
stylis: 4.2.0
|
||||||
|
|
||||||
|
'@emotion/css@11.13.5':
|
||||||
|
dependencies:
|
||||||
|
'@emotion/babel-plugin': 11.13.5
|
||||||
|
'@emotion/cache': 11.14.0
|
||||||
|
'@emotion/serialize': 1.3.3
|
||||||
|
'@emotion/sheet': 1.4.0
|
||||||
|
'@emotion/utils': 1.4.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
'@emotion/hash@0.8.0': {}
|
'@emotion/hash@0.8.0': {}
|
||||||
|
|
||||||
|
'@emotion/hash@0.9.2': {}
|
||||||
|
|
||||||
'@emotion/is-prop-valid@1.2.2':
|
'@emotion/is-prop-valid@1.2.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@emotion/memoize': 0.8.1
|
'@emotion/memoize': 0.8.1
|
||||||
|
|
||||||
'@emotion/memoize@0.8.1': {}
|
'@emotion/memoize@0.8.1': {}
|
||||||
|
|
||||||
|
'@emotion/memoize@0.9.0': {}
|
||||||
|
|
||||||
|
'@emotion/serialize@1.3.3':
|
||||||
|
dependencies:
|
||||||
|
'@emotion/hash': 0.9.2
|
||||||
|
'@emotion/memoize': 0.9.0
|
||||||
|
'@emotion/unitless': 0.10.0
|
||||||
|
'@emotion/utils': 1.4.2
|
||||||
|
csstype: 3.1.3
|
||||||
|
|
||||||
|
'@emotion/sheet@1.4.0': {}
|
||||||
|
|
||||||
|
'@emotion/unitless@0.10.0': {}
|
||||||
|
|
||||||
'@emotion/unitless@0.7.5': {}
|
'@emotion/unitless@0.7.5': {}
|
||||||
|
|
||||||
'@emotion/unitless@0.8.1': {}
|
'@emotion/unitless@0.8.1': {}
|
||||||
|
|
||||||
|
'@emotion/utils@1.4.2': {}
|
||||||
|
|
||||||
|
'@emotion/weak-memoize@0.4.0': {}
|
||||||
|
|
||||||
'@iconify/react@4.1.1(react@19.1.0)':
|
'@iconify/react@4.1.1(react@19.1.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@iconify/types': 2.0.0
|
'@iconify/types': 2.0.0
|
||||||
@@ -2535,6 +2889,13 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
sparse-bitfield: 3.0.3
|
sparse-bitfield: 3.0.3
|
||||||
|
|
||||||
|
'@next/bundle-analyzer@15.3.3':
|
||||||
|
dependencies:
|
||||||
|
webpack-bundle-analyzer: 4.10.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
'@next/env@15.3.3': {}
|
'@next/env@15.3.3': {}
|
||||||
|
|
||||||
'@next/swc-darwin-arm64@15.3.3':
|
'@next/swc-darwin-arm64@15.3.3':
|
||||||
@@ -2561,6 +2922,8 @@ snapshots:
|
|||||||
'@next/swc-win32-x64-msvc@15.3.3':
|
'@next/swc-win32-x64-msvc@15.3.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@polka/url@1.0.0-next.29': {}
|
||||||
|
|
||||||
'@rc-component/async-validator@5.0.4':
|
'@rc-component/async-validator@5.0.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.27.4
|
'@babel/runtime': 7.27.4
|
||||||
@@ -2772,6 +3135,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.19.8
|
undici-types: 6.19.8
|
||||||
|
|
||||||
|
'@types/parse-json@4.0.2': {}
|
||||||
|
|
||||||
'@types/ramda@0.30.2':
|
'@types/ramda@0.30.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
types-ramda: 0.30.1
|
types-ramda: 0.30.1
|
||||||
@@ -2821,6 +3186,12 @@ snapshots:
|
|||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
negotiator: 0.6.3
|
negotiator: 0.6.3
|
||||||
|
|
||||||
|
acorn-walk@8.3.4:
|
||||||
|
dependencies:
|
||||||
|
acorn: 8.15.0
|
||||||
|
|
||||||
|
acorn@8.15.0: {}
|
||||||
|
|
||||||
add-dom-event-listener@1.1.0:
|
add-dom-event-listener@1.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
@@ -2894,6 +3265,12 @@ snapshots:
|
|||||||
'@svgdotjs/svg.select.js': 4.0.3(@svgdotjs/svg.js@3.2.4)
|
'@svgdotjs/svg.select.js': 4.0.3(@svgdotjs/svg.js@3.2.4)
|
||||||
'@yr/monotone-cubic-spline': 1.0.3
|
'@yr/monotone-cubic-spline': 1.0.3
|
||||||
|
|
||||||
|
babel-plugin-macros@3.1.0:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.27.4
|
||||||
|
cosmiconfig: 7.1.0
|
||||||
|
resolve: 1.22.10
|
||||||
|
|
||||||
bail@2.0.2: {}
|
bail@2.0.2: {}
|
||||||
|
|
||||||
base64id@2.0.0: {}
|
base64id@2.0.0: {}
|
||||||
@@ -2908,6 +3285,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
streamsearch: 1.1.0
|
streamsearch: 1.1.0
|
||||||
|
|
||||||
|
callsites@3.1.0: {}
|
||||||
|
|
||||||
camelize@1.0.1: {}
|
camelize@1.0.1: {}
|
||||||
|
|
||||||
caniuse-lite@1.0.30001720: {}
|
caniuse-lite@1.0.30001720: {}
|
||||||
@@ -2972,8 +3351,12 @@ snapshots:
|
|||||||
|
|
||||||
comma-separated-tokens@2.0.3: {}
|
comma-separated-tokens@2.0.3: {}
|
||||||
|
|
||||||
|
commander@7.2.0: {}
|
||||||
|
|
||||||
compute-scroll-into-view@3.1.1: {}
|
compute-scroll-into-view@3.1.1: {}
|
||||||
|
|
||||||
|
convert-source-map@1.9.0: {}
|
||||||
|
|
||||||
cookie@0.7.2: {}
|
cookie@0.7.2: {}
|
||||||
|
|
||||||
copy-to-clipboard@3.3.3:
|
copy-to-clipboard@3.3.3:
|
||||||
@@ -2985,6 +3368,14 @@ snapshots:
|
|||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
vary: 1.1.2
|
vary: 1.1.2
|
||||||
|
|
||||||
|
cosmiconfig@7.1.0:
|
||||||
|
dependencies:
|
||||||
|
'@types/parse-json': 4.0.2
|
||||||
|
import-fresh: 3.3.1
|
||||||
|
parse-json: 5.2.0
|
||||||
|
path-type: 4.0.0
|
||||||
|
yaml: 1.10.2
|
||||||
|
|
||||||
crc-32@1.2.2: {}
|
crc-32@1.2.2: {}
|
||||||
|
|
||||||
css-color-keywords@1.0.0: {}
|
css-color-keywords@1.0.0: {}
|
||||||
@@ -2999,6 +3390,8 @@ snapshots:
|
|||||||
|
|
||||||
dayjs@1.11.13: {}
|
dayjs@1.11.13: {}
|
||||||
|
|
||||||
|
debounce@1.2.1: {}
|
||||||
|
|
||||||
debug@4.3.7:
|
debug@4.3.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
@@ -3019,6 +3412,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
|
|
||||||
|
duplexer@0.1.2: {}
|
||||||
|
|
||||||
ecdsa-sig-formatter@1.0.11:
|
ecdsa-sig-formatter@1.0.11:
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
@@ -3072,6 +3467,12 @@ snapshots:
|
|||||||
|
|
||||||
entities@6.0.1: {}
|
entities@6.0.1: {}
|
||||||
|
|
||||||
|
error-ex@1.3.2:
|
||||||
|
dependencies:
|
||||||
|
is-arrayish: 0.2.1
|
||||||
|
|
||||||
|
escape-string-regexp@4.0.0: {}
|
||||||
|
|
||||||
escape-string-regexp@5.0.0: {}
|
escape-string-regexp@5.0.0: {}
|
||||||
|
|
||||||
estree-util-is-identifier-name@3.0.0: {}
|
estree-util-is-identifier-name@3.0.0: {}
|
||||||
@@ -3082,14 +3483,28 @@ snapshots:
|
|||||||
|
|
||||||
file-saver@2.0.5: {}
|
file-saver@2.0.5: {}
|
||||||
|
|
||||||
|
find-root@1.1.0: {}
|
||||||
|
|
||||||
frac@1.1.2: {}
|
frac@1.1.2: {}
|
||||||
|
|
||||||
|
function-bind@1.1.2: {}
|
||||||
|
|
||||||
geist@1.4.2(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)):
|
geist@1.4.2(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)):
|
||||||
dependencies:
|
dependencies:
|
||||||
next: 15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
next: 15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
|
||||||
|
globals@11.12.0: {}
|
||||||
|
|
||||||
graceful-fs@4.2.11: {}
|
graceful-fs@4.2.11: {}
|
||||||
|
|
||||||
|
gzip-size@6.0.0:
|
||||||
|
dependencies:
|
||||||
|
duplexer: 0.1.2
|
||||||
|
|
||||||
|
hasown@2.0.2:
|
||||||
|
dependencies:
|
||||||
|
function-bind: 1.1.2
|
||||||
|
|
||||||
hast-util-from-parse5@8.0.3:
|
hast-util-from-parse5@8.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/hast': 3.0.4
|
'@types/hast': 3.0.4
|
||||||
@@ -3176,10 +3591,17 @@ snapshots:
|
|||||||
|
|
||||||
highlight.js@11.11.1: {}
|
highlight.js@11.11.1: {}
|
||||||
|
|
||||||
|
html-escaper@2.0.2: {}
|
||||||
|
|
||||||
html-url-attributes@3.0.1: {}
|
html-url-attributes@3.0.1: {}
|
||||||
|
|
||||||
html-void-elements@3.0.0: {}
|
html-void-elements@3.0.0: {}
|
||||||
|
|
||||||
|
import-fresh@3.3.1:
|
||||||
|
dependencies:
|
||||||
|
parent-module: 1.0.1
|
||||||
|
resolve-from: 4.0.0
|
||||||
|
|
||||||
inline-style-parser@0.2.4: {}
|
inline-style-parser@0.2.4: {}
|
||||||
|
|
||||||
is-alphabetical@2.0.1: {}
|
is-alphabetical@2.0.1: {}
|
||||||
@@ -3189,19 +3611,31 @@ snapshots:
|
|||||||
is-alphabetical: 2.0.1
|
is-alphabetical: 2.0.1
|
||||||
is-decimal: 2.0.1
|
is-decimal: 2.0.1
|
||||||
|
|
||||||
|
is-arrayish@0.2.1: {}
|
||||||
|
|
||||||
is-arrayish@0.3.2:
|
is-arrayish@0.3.2:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
is-core-module@2.16.1:
|
||||||
|
dependencies:
|
||||||
|
hasown: 2.0.2
|
||||||
|
|
||||||
is-decimal@2.0.1: {}
|
is-decimal@2.0.1: {}
|
||||||
|
|
||||||
is-hexadecimal@2.0.1: {}
|
is-hexadecimal@2.0.1: {}
|
||||||
|
|
||||||
is-plain-obj@4.1.0: {}
|
is-plain-obj@4.1.0: {}
|
||||||
|
|
||||||
|
is-plain-object@5.0.0: {}
|
||||||
|
|
||||||
jiti@2.4.2: {}
|
jiti@2.4.2: {}
|
||||||
|
|
||||||
js-tokens@4.0.0: {}
|
js-tokens@4.0.0: {}
|
||||||
|
|
||||||
|
jsesc@3.1.0: {}
|
||||||
|
|
||||||
|
json-parse-even-better-errors@2.3.1: {}
|
||||||
|
|
||||||
json2mq@0.2.0:
|
json2mq@0.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
string-convert: 0.2.1
|
string-convert: 0.2.1
|
||||||
@@ -3277,6 +3711,8 @@ snapshots:
|
|||||||
lightningcss-win32-arm64-msvc: 1.30.1
|
lightningcss-win32-arm64-msvc: 1.30.1
|
||||||
lightningcss-win32-x64-msvc: 1.30.1
|
lightningcss-win32-x64-msvc: 1.30.1
|
||||||
|
|
||||||
|
lines-and-columns@1.2.4: {}
|
||||||
|
|
||||||
lodash-es@4.17.21: {}
|
lodash-es@4.17.21: {}
|
||||||
|
|
||||||
lodash.includes@4.3.0: {}
|
lodash.includes@4.3.0: {}
|
||||||
@@ -3711,6 +4147,8 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
mrmime@2.0.1: {}
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
nanoid@3.3.11: {}
|
nanoid@3.3.11: {}
|
||||||
@@ -3744,6 +4182,12 @@ snapshots:
|
|||||||
|
|
||||||
object-assign@4.1.1: {}
|
object-assign@4.1.1: {}
|
||||||
|
|
||||||
|
opener@1.5.2: {}
|
||||||
|
|
||||||
|
parent-module@1.0.1:
|
||||||
|
dependencies:
|
||||||
|
callsites: 3.1.0
|
||||||
|
|
||||||
parse-entities@4.0.2:
|
parse-entities@4.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/unist': 2.0.11
|
'@types/unist': 2.0.11
|
||||||
@@ -3754,12 +4198,23 @@ snapshots:
|
|||||||
is-decimal: 2.0.1
|
is-decimal: 2.0.1
|
||||||
is-hexadecimal: 2.0.1
|
is-hexadecimal: 2.0.1
|
||||||
|
|
||||||
|
parse-json@5.2.0:
|
||||||
|
dependencies:
|
||||||
|
'@babel/code-frame': 7.27.1
|
||||||
|
error-ex: 1.3.2
|
||||||
|
json-parse-even-better-errors: 2.3.1
|
||||||
|
lines-and-columns: 1.2.4
|
||||||
|
|
||||||
parse5@7.3.0:
|
parse5@7.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
entities: 6.0.1
|
entities: 6.0.1
|
||||||
|
|
||||||
|
path-parse@1.0.7: {}
|
||||||
|
|
||||||
path-to-regexp@8.2.0: {}
|
path-to-regexp@8.2.0: {}
|
||||||
|
|
||||||
|
path-type@4.0.0: {}
|
||||||
|
|
||||||
picocolors@1.1.1: {}
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
postcss-value-parser@4.2.0: {}
|
postcss-value-parser@4.2.0: {}
|
||||||
@@ -4233,6 +4688,14 @@ snapshots:
|
|||||||
|
|
||||||
resize-observer-polyfill@1.5.1: {}
|
resize-observer-polyfill@1.5.1: {}
|
||||||
|
|
||||||
|
resolve-from@4.0.0: {}
|
||||||
|
|
||||||
|
resolve@1.22.10:
|
||||||
|
dependencies:
|
||||||
|
is-core-module: 2.16.1
|
||||||
|
path-parse: 1.0.7
|
||||||
|
supports-preserve-symlinks-flag: 1.0.0
|
||||||
|
|
||||||
safe-buffer@5.2.1: {}
|
safe-buffer@5.2.1: {}
|
||||||
|
|
||||||
safe-stable-stringify@2.5.0: {}
|
safe-stable-stringify@2.5.0: {}
|
||||||
@@ -4283,6 +4746,12 @@ snapshots:
|
|||||||
is-arrayish: 0.3.2
|
is-arrayish: 0.3.2
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
sirv@2.0.4:
|
||||||
|
dependencies:
|
||||||
|
'@polka/url': 1.0.0-next.29
|
||||||
|
mrmime: 2.0.1
|
||||||
|
totalist: 3.0.1
|
||||||
|
|
||||||
size-sensor@1.0.2: {}
|
size-sensor@1.0.2: {}
|
||||||
|
|
||||||
socket.io-adapter@2.5.5:
|
socket.io-adapter@2.5.5:
|
||||||
@@ -4328,6 +4797,8 @@ snapshots:
|
|||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
source-map@0.5.7: {}
|
||||||
|
|
||||||
space-separated-tokens@2.0.2: {}
|
space-separated-tokens@2.0.2: {}
|
||||||
|
|
||||||
sparse-bitfield@3.0.3:
|
sparse-bitfield@3.0.3:
|
||||||
@@ -4374,10 +4845,14 @@ snapshots:
|
|||||||
client-only: 0.0.1
|
client-only: 0.0.1
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
|
|
||||||
|
stylis@4.2.0: {}
|
||||||
|
|
||||||
stylis@4.3.2: {}
|
stylis@4.3.2: {}
|
||||||
|
|
||||||
stylis@4.3.6: {}
|
stylis@4.3.6: {}
|
||||||
|
|
||||||
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
swr@2.3.3(react@19.1.0):
|
swr@2.3.3(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
dequal: 2.0.3
|
dequal: 2.0.3
|
||||||
@@ -4403,6 +4878,8 @@ snapshots:
|
|||||||
|
|
||||||
toggle-selection@1.0.6: {}
|
toggle-selection@1.0.6: {}
|
||||||
|
|
||||||
|
totalist@3.0.1: {}
|
||||||
|
|
||||||
tr46@5.1.1:
|
tr46@5.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
punycode: 2.3.1
|
punycode: 2.3.1
|
||||||
@@ -4496,6 +4973,25 @@ snapshots:
|
|||||||
|
|
||||||
webidl-conversions@7.0.0: {}
|
webidl-conversions@7.0.0: {}
|
||||||
|
|
||||||
|
webpack-bundle-analyzer@4.10.1:
|
||||||
|
dependencies:
|
||||||
|
'@discoveryjs/json-ext': 0.5.7
|
||||||
|
acorn: 8.15.0
|
||||||
|
acorn-walk: 8.3.4
|
||||||
|
commander: 7.2.0
|
||||||
|
debounce: 1.2.1
|
||||||
|
escape-string-regexp: 4.0.0
|
||||||
|
gzip-size: 6.0.0
|
||||||
|
html-escaper: 2.0.2
|
||||||
|
is-plain-object: 5.0.0
|
||||||
|
opener: 1.5.2
|
||||||
|
picocolors: 1.1.1
|
||||||
|
sirv: 2.0.4
|
||||||
|
ws: 7.5.10
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- bufferutil
|
||||||
|
- utf-8-validate
|
||||||
|
|
||||||
whatwg-url@14.2.0:
|
whatwg-url@14.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
tr46: 5.1.1
|
tr46: 5.1.1
|
||||||
@@ -4505,6 +5001,8 @@ snapshots:
|
|||||||
|
|
||||||
word@0.3.0: {}
|
word@0.3.0: {}
|
||||||
|
|
||||||
|
ws@7.5.10: {}
|
||||||
|
|
||||||
ws@8.17.1: {}
|
ws@8.17.1: {}
|
||||||
|
|
||||||
xlsx@0.18.5:
|
xlsx@0.18.5:
|
||||||
@@ -4521,6 +5019,8 @@ snapshots:
|
|||||||
|
|
||||||
yallist@5.0.0: {}
|
yallist@5.0.0: {}
|
||||||
|
|
||||||
|
yaml@1.10.2: {}
|
||||||
|
|
||||||
zrender@5.6.1:
|
zrender@5.6.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.3.0
|
tslib: 2.3.0
|
||||||
|
|||||||
@@ -1,170 +0,0 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
|
||||||
import { Button, message, Popover } from 'antd';
|
|
||||||
import { PoweroffOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
// 自定义 Hook,用于管理定时器
|
|
||||||
function useInterval(callback: () => void, delay: number | null) {
|
|
||||||
const savedCallback = useRef<() => void>(() => {});
|
|
||||||
|
|
||||||
// 保存最新的回调函数,以便在定时器触发时使用
|
|
||||||
useEffect(() => {
|
|
||||||
savedCallback.current = callback;
|
|
||||||
}, [callback]);
|
|
||||||
|
|
||||||
// 当 delay 发生变化时,设置或清除定时器
|
|
||||||
useEffect(() => {
|
|
||||||
if (delay !== null) {
|
|
||||||
const id = setInterval(() => savedCallback.current && savedCallback.current(), delay);
|
|
||||||
return () => clearInterval(id); // 清除定时器以防止内存泄漏
|
|
||||||
}
|
|
||||||
}, [delay]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const TaskController: React.FC = () => {
|
|
||||||
// 剩余时间的状态
|
|
||||||
const [remainingTime, setRemainingTime] = useState<number | null>(null);
|
|
||||||
// 是否正在计时的状态
|
|
||||||
const [isCounting, setIsCounting] = useState<boolean>(false);
|
|
||||||
// 用于存储 EventSource 的引用
|
|
||||||
const eventSourceRef = useRef<EventSource | null>(null);
|
|
||||||
const lastQueryResultRef = useRef<string | null>(null); // 用于存储上次查询的结果
|
|
||||||
|
|
||||||
// 开始任务并启动倒计时的函数
|
|
||||||
const startTask = async () => {
|
|
||||||
if (!isCounting) {
|
|
||||||
setIsCounting(true);
|
|
||||||
// 在计时开始时进行物流查询
|
|
||||||
await updateLogisticsDetails();
|
|
||||||
console.log('使用 EventSource 启动倒计时...');
|
|
||||||
|
|
||||||
// 启动 SSE 连接
|
|
||||||
const eventSource = new EventSource('/api/sse');
|
|
||||||
eventSourceRef.current = eventSource;
|
|
||||||
|
|
||||||
// 当 SSE 连接成功时触发
|
|
||||||
eventSource.onopen = () => {
|
|
||||||
console.log('客户端 SSE 连接已打开');
|
|
||||||
};
|
|
||||||
|
|
||||||
// 当收到服务器发送的消息时触发
|
|
||||||
eventSource.onmessage = (event) => {
|
|
||||||
const time = parseInt(event.data, 10);
|
|
||||||
setRemainingTime(time);
|
|
||||||
//console.log('接收到事件:', time);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 当发生错误时触发
|
|
||||||
eventSource.onerror = (error) => {
|
|
||||||
console.error('SSE 错误:', error);
|
|
||||||
eventSource.close();
|
|
||||||
setIsCounting(false); // 关闭倒计时
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 本地定时器,每秒更新 UI 中的剩余时间
|
|
||||||
useInterval(() => {
|
|
||||||
if (remainingTime !== null && remainingTime > 0) {
|
|
||||||
setRemainingTime(remainingTime - 1);
|
|
||||||
} else if (remainingTime === 0) {
|
|
||||||
// 移除或注释掉关闭 SSE 连接的代码
|
|
||||||
//if (eventSourceRef.current) {
|
|
||||||
// eventSourceRef.current.close(); // 关闭 SSE 连接
|
|
||||||
//}
|
|
||||||
setIsCounting(false); // 停止倒计时
|
|
||||||
startTask(); // 计时结束后自动开始新的一轮查询
|
|
||||||
}
|
|
||||||
}, isCounting ? 1000 : null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// 页面加载时检查是否有剩余时间
|
|
||||||
if (remainingTime === null) {
|
|
||||||
// 创建 EventSource 连接以检查服务器端是否有剩余时间
|
|
||||||
const eventSource = new EventSource('/api/sse');
|
|
||||||
eventSourceRef.current = eventSource;
|
|
||||||
|
|
||||||
eventSource.onmessage = (event) => {
|
|
||||||
const time = parseInt(event.data, 10);
|
|
||||||
setRemainingTime(time);
|
|
||||||
if (time > 0) {
|
|
||||||
setIsCounting(true); // 如果有剩余时间,则开始倒计时
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
eventSource.onerror = (error) => {
|
|
||||||
console.error('SSE 错误:', error);
|
|
||||||
eventSource.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
// 检查本地存储或其他持久化方式,恢复上次查询结果
|
|
||||||
const savedLastQueryResult = localStorage.getItem('lastQueryResult');
|
|
||||||
if (savedLastQueryResult) {
|
|
||||||
lastQueryResultRef.current = savedLastQueryResult; // 恢复查询结果
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在组件卸载时关闭 SSE 连接,防止内存泄漏
|
|
||||||
return () => {
|
|
||||||
if (eventSourceRef.current) {
|
|
||||||
eventSourceRef.current.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}, [remainingTime]);
|
|
||||||
|
|
||||||
// 物流查询并保存结果的函数
|
|
||||||
const updateLogisticsDetails = async () => {
|
|
||||||
try {
|
|
||||||
const response = await fetch('/api/tools/SFExpress/updateLogisticsDetails', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// 处理响应数据
|
|
||||||
const data = await response.json();
|
|
||||||
message.success('更新物流详情成功');
|
|
||||||
//console.log('更新物流详情成功:', data);
|
|
||||||
lastQueryResultRef.current = data.message;
|
|
||||||
// 将查询结果保存到 localStorage
|
|
||||||
localStorage.setItem('lastQueryResult', data.message);
|
|
||||||
} catch (error) {
|
|
||||||
message.error('更新物流详情失败');
|
|
||||||
//console.error('更新物流详情失败:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 用于显示在 Popover 中的内容
|
|
||||||
/*const popoverContent = (
|
|
||||||
<div>
|
|
||||||
{lastQueryResultRef.current ? (
|
|
||||||
<p>{lastQueryResultRef.current}</p>
|
|
||||||
) : (
|
|
||||||
<p>暂无最新物流详情</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);*/
|
|
||||||
|
|
||||||
// 计算按钮显示的文字
|
|
||||||
const displayText = isCounting ? `剩余: ${remainingTime} 秒` : '物流查询';
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Popover
|
|
||||||
//content={popoverContent}
|
|
||||||
//title="最新物流详情"
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
className="text-white bg-blue-500 hover:bg-blue-700"
|
|
||||||
type="primary"
|
|
||||||
icon={<PoweroffOutlined />}
|
|
||||||
loading={isCounting} // 按钮加载状态取决于是否在计时中
|
|
||||||
onClick={startTask} // 点击按钮启动任务
|
|
||||||
disabled={isCounting || (remainingTime !== null && remainingTime > 0)} // 在计时中或剩余时间大于0时禁用按钮
|
|
||||||
>
|
|
||||||
{displayText}
|
|
||||||
</Button>
|
|
||||||
</Popover>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TaskController;
|
|
||||||
@@ -426,10 +426,10 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
|||||||
// PageContainer 内边距控制 - 完全移除左右空白
|
// PageContainer 内边距控制 - 完全移除左右空白
|
||||||
pageContainer: {
|
pageContainer: {
|
||||||
// 移除 PageContainer 内容区域的上下内边距 (Block 方向,即垂直方向)
|
// 移除 PageContainer 内容区域的上下内边距 (Block 方向,即垂直方向)
|
||||||
paddingBlockPageContainerContent: 0,
|
//paddingBlockPageContainerContent: 0,
|
||||||
// 移除 PageContainer 内容区域的左右内边距 (Inline 方向,即水平方向)
|
// 移除 PageContainer 内容区域的左右内边距 (Inline 方向,即水平方向)
|
||||||
// 这是消除左右空白的关键配置之一
|
// 这是消除左右空白的关键配置之一
|
||||||
paddingInlinePageContainerContent: 0,
|
//paddingInlinePageContainerContent: 0,
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
siderMenuType="group"
|
siderMenuType="group"
|
||||||
@@ -463,23 +463,6 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
|||||||
contentWidth="Fluid"
|
contentWidth="Fluid"
|
||||||
locale="zh-CN"
|
locale="zh-CN"
|
||||||
>
|
>
|
||||||
{/*
|
|
||||||
内容区域边距移除方案说明:
|
|
||||||
|
|
||||||
为了完全移除页面内容的左右空白,采用了三层防护措施:
|
|
||||||
|
|
||||||
1. ProLayout 层级:通过 token.pageContainer.paddingInlinePageContainerContent = 0
|
|
||||||
移除 ProLayout 组件默认的左右内边距
|
|
||||||
|
|
||||||
2. PageContainer 层级:
|
|
||||||
- pageHeaderRender={false} 禁用头部渲染避免额外空间
|
|
||||||
- token.paddingInlinePageContainerContent = 0 再次确保移除左右内边距
|
|
||||||
- style.padding = 0 移除组件自身样式内边距
|
|
||||||
|
|
||||||
3. 最内层 div:padding = '0px' 作为最后一道防线
|
|
||||||
|
|
||||||
这样的多层配置确保在不同版本的 Ant Design Pro 中都能正常工作
|
|
||||||
*/}
|
|
||||||
<PageContainer
|
<PageContainer
|
||||||
// 移除默认的页面标题栏
|
// 移除默认的页面标题栏
|
||||||
header={{ title: null }}
|
header={{ title: null }}
|
||||||
@@ -514,6 +497,8 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
|||||||
margin: 0,
|
margin: 0,
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
|
//background: 'blue',
|
||||||
|
//height: '90vh',
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
@@ -528,7 +513,7 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
|||||||
open={showPersonalInfo}
|
open={showPersonalInfo}
|
||||||
onCancel={handleClosePersonalInfo}
|
onCancel={handleClosePersonalInfo}
|
||||||
footer={null}
|
footer={null}
|
||||||
width={800}
|
width='80%'
|
||||||
destroyOnHidden
|
destroyOnHidden
|
||||||
>
|
>
|
||||||
<PersonalInfo />
|
<PersonalInfo />
|
||||||
|
|||||||
456
src/components/layout/Layout.tsx.bak
Normal file
456
src/components/layout/Layout.tsx.bak
Normal file
@@ -0,0 +1,456 @@
|
|||||||
|
import {
|
||||||
|
CaretDownFilled,
|
||||||
|
DoubleRightOutlined,
|
||||||
|
GithubFilled,
|
||||||
|
InfoCircleFilled,
|
||||||
|
LogoutOutlined,
|
||||||
|
PlusCircleFilled,
|
||||||
|
QuestionCircleFilled,
|
||||||
|
SearchOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import type { ProSettings } from '@ant-design/pro-components';
|
||||||
|
import {
|
||||||
|
PageContainer,
|
||||||
|
ProCard,
|
||||||
|
ProConfigProvider,
|
||||||
|
ProLayout,
|
||||||
|
SettingDrawer,
|
||||||
|
} from '@ant-design/pro-components';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
ConfigProvider,
|
||||||
|
Divider,
|
||||||
|
Dropdown,
|
||||||
|
Input,
|
||||||
|
Popover,
|
||||||
|
theme,
|
||||||
|
} from 'antd';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import defaultProps from './_defaultProps';
|
||||||
|
|
||||||
|
const Item: React.FC<{ children: React.ReactNode }> = (props) => {
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
color: ${token.colorTextSecondary};
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 22px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
&:hover {
|
||||||
|
color: ${token.colorPrimary};
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
style={{
|
||||||
|
width: '33.33%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
<DoubleRightOutlined
|
||||||
|
style={{
|
||||||
|
marginInlineStart: 4,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const List: React.FC<{ title: string; style?: React.CSSProperties }> = (
|
||||||
|
props,
|
||||||
|
) => {
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
...props.style,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: token.colorTextHeading,
|
||||||
|
lineHeight: '24px',
|
||||||
|
fontWeight: 500,
|
||||||
|
marginBlockEnd: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.title}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{new Array(6).fill(1).map((_, index) => {
|
||||||
|
return <Item key={index}>具体的解决方案-{index}</Item>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const MenuCard = () => {
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Divider
|
||||||
|
style={{
|
||||||
|
height: '1.5em',
|
||||||
|
}}
|
||||||
|
type="vertical"
|
||||||
|
/>
|
||||||
|
<Popover
|
||||||
|
placement="bottom"
|
||||||
|
overlayStyle={{
|
||||||
|
width: 'calc(100vw - 24px)',
|
||||||
|
padding: '24px',
|
||||||
|
paddingTop: 8,
|
||||||
|
height: '307px',
|
||||||
|
borderRadius: '0 0 6px 6px',
|
||||||
|
}}
|
||||||
|
content={
|
||||||
|
<div style={{ display: 'flex', padding: '32px 40px' }}>
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<List title="金融解决方案" />
|
||||||
|
<List
|
||||||
|
title="其他解决方案"
|
||||||
|
style={{
|
||||||
|
marginBlockStart: 32,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: '308px',
|
||||||
|
borderInlineStart: '1px solid ' + token.colorBorder,
|
||||||
|
paddingInlineStart: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
font-size: 14px;
|
||||||
|
color: ${token.colorText};
|
||||||
|
line-height: 22px;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
热门产品
|
||||||
|
</div>
|
||||||
|
{new Array(3).fill(1).map((_name, index) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className={css`
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-top: 4px;
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background-color: ${token.colorBgTextHover};
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<img src="https://gw.alipayobjects.com/zos/antfincdn/6FTGmLLmN/bianzu%25252013.svg" />
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginInlineStart: 14,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
font-size: 14px;
|
||||||
|
color: ${token.colorText};
|
||||||
|
line-height: 22px;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
Ant Design
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
font-size: 12px;
|
||||||
|
color: ${token.colorTextSecondary};
|
||||||
|
line-height: 20px;
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
杭州市较知名的 UI 设计语言
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
color: token.colorTextHeading,
|
||||||
|
fontWeight: 500,
|
||||||
|
cursor: 'pointer',
|
||||||
|
display: 'flex',
|
||||||
|
gap: 4,
|
||||||
|
paddingInlineStart: 8,
|
||||||
|
paddingInlineEnd: 12,
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
className={css`
|
||||||
|
&:hover {
|
||||||
|
background-color: ${token.colorBgTextHover};
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<span> 企业级资产中心</span>
|
||||||
|
<CaretDownFilled />
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SearchInput = () => {
|
||||||
|
const { token } = theme.useToken();
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key="SearchOutlined"
|
||||||
|
aria-hidden
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginInlineEnd: 24,
|
||||||
|
}}
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
style={{
|
||||||
|
borderRadius: 4,
|
||||||
|
marginInlineEnd: 12,
|
||||||
|
backgroundColor: token.colorBgTextHover,
|
||||||
|
}}
|
||||||
|
prefix={
|
||||||
|
<SearchOutlined
|
||||||
|
style={{
|
||||||
|
color: token.colorTextLightSolid,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
placeholder="搜索方案"
|
||||||
|
variant="borderless"
|
||||||
|
/>
|
||||||
|
<PlusCircleFilled
|
||||||
|
style={{
|
||||||
|
color: token.colorPrimary,
|
||||||
|
fontSize: 24,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const [settings, setSetting] = useState<Partial<ProSettings> | undefined>({
|
||||||
|
fixSiderbar: true,
|
||||||
|
layout: 'mix',
|
||||||
|
splitMenus: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [pathname, setPathname] = useState('/list/sub-page/sub-sub-page1');
|
||||||
|
const [num, setNum] = useState(40);
|
||||||
|
if (typeof document === 'undefined') {
|
||||||
|
return <div />;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id="test-pro-layout"
|
||||||
|
style={{
|
||||||
|
height: '100vh',
|
||||||
|
overflow: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ProConfigProvider hashed={false}>
|
||||||
|
<ConfigProvider
|
||||||
|
getTargetContainer={() => {
|
||||||
|
return document.getElementById('test-pro-layout') || document.body;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ProLayout
|
||||||
|
prefixCls="my-prefix"
|
||||||
|
bgLayoutImgList={[
|
||||||
|
{
|
||||||
|
src: 'https://img.alicdn.com/imgextra/i2/O1CN01O4etvp1DvpFLKfuWq_!!6000000000279-2-tps-609-606.png',
|
||||||
|
left: 85,
|
||||||
|
bottom: 100,
|
||||||
|
height: '303px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'https://img.alicdn.com/imgextra/i2/O1CN01O4etvp1DvpFLKfuWq_!!6000000000279-2-tps-609-606.png',
|
||||||
|
bottom: -68,
|
||||||
|
right: -45,
|
||||||
|
height: '303px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'https://img.alicdn.com/imgextra/i3/O1CN018NxReL1shX85Yz6Cx_!!6000000005798-2-tps-884-496.png',
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
width: '331px',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
{...defaultProps}
|
||||||
|
location={{
|
||||||
|
pathname,
|
||||||
|
}}
|
||||||
|
token={{
|
||||||
|
header: {
|
||||||
|
colorBgMenuItemSelected: 'rgba(0,0,0,0.04)',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
siderMenuType="group"
|
||||||
|
menu={{
|
||||||
|
collapsedShowGroupTitle: true,
|
||||||
|
}}
|
||||||
|
avatarProps={{
|
||||||
|
src: 'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
|
||||||
|
size: 'small',
|
||||||
|
title: '七妮妮',
|
||||||
|
render: (_props, dom) => {
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
menu={{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
key: 'logout',
|
||||||
|
icon: <LogoutOutlined />,
|
||||||
|
label: '退出登录',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dom}
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
actionsRender={(props) => {
|
||||||
|
if (props.isMobile) return [];
|
||||||
|
if (typeof window === 'undefined') return [];
|
||||||
|
return [
|
||||||
|
props.layout !== 'side' && document.body.clientWidth > 1400 ? (
|
||||||
|
<SearchInput />
|
||||||
|
) : undefined,
|
||||||
|
<InfoCircleFilled key="InfoCircleFilled" />,
|
||||||
|
<QuestionCircleFilled key="QuestionCircleFilled" />,
|
||||||
|
<GithubFilled key="GithubFilled" />,
|
||||||
|
];
|
||||||
|
}}
|
||||||
|
headerTitleRender={(logo, title, _) => {
|
||||||
|
const defaultDom = (
|
||||||
|
<a>
|
||||||
|
{logo}
|
||||||
|
{title}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
if (typeof window === 'undefined') return defaultDom;
|
||||||
|
if (document.body.clientWidth < 1400) {
|
||||||
|
return defaultDom;
|
||||||
|
}
|
||||||
|
if (_.isMobile) return defaultDom;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{defaultDom}
|
||||||
|
<MenuCard />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
menuFooterRender={(props) => {
|
||||||
|
if (props?.collapsed) return undefined;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
textAlign: 'center',
|
||||||
|
paddingBlockStart: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>© 2021 Made with love</div>
|
||||||
|
<div>by Ant Design</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
onMenuHeaderClick={(e) => console.log(e)}
|
||||||
|
menuItemRender={(item, dom) => (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
setPathname(item.path || '/welcome');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dom}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{...settings}
|
||||||
|
>
|
||||||
|
<PageContainer
|
||||||
|
token={{
|
||||||
|
paddingInlinePageContainerContent: num,
|
||||||
|
}}
|
||||||
|
extra={[
|
||||||
|
<Button key="3">操作</Button>,
|
||||||
|
<Button key="2">操作</Button>,
|
||||||
|
<Button
|
||||||
|
key="1"
|
||||||
|
type="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setNum(num > 0 ? 0 : 40);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
主操作
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
subTitle="简单的描述"
|
||||||
|
footer={[
|
||||||
|
<Button key="3">重置</Button>,
|
||||||
|
<Button key="2" type="primary">
|
||||||
|
提交
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<ProCard
|
||||||
|
style={{
|
||||||
|
height: '200vh',
|
||||||
|
minHeight: 800,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div />
|
||||||
|
</ProCard>
|
||||||
|
</PageContainer>
|
||||||
|
|
||||||
|
<SettingDrawer
|
||||||
|
pathname={pathname}
|
||||||
|
enableDarkTheme
|
||||||
|
getContainer={(e: any) => {
|
||||||
|
if (typeof window === 'undefined') return e;
|
||||||
|
return document.getElementById('test-pro-layout');
|
||||||
|
}}
|
||||||
|
settings={settings}
|
||||||
|
onSettingChange={(changeSetting) => {
|
||||||
|
setSetting(changeSetting);
|
||||||
|
}}
|
||||||
|
disableUrlParams={false}
|
||||||
|
/>
|
||||||
|
</ProLayout>
|
||||||
|
</ConfigProvider>
|
||||||
|
</ProConfigProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
// src/components/layout/Navbar.tsx
|
|
||||||
import React from 'react';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import { HomeOutlined, LockOutlined, MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined } from '@ant-design/icons';
|
|
||||||
|
|
||||||
interface NavbarProps {
|
|
||||||
isCollapsed: boolean;
|
|
||||||
setIsCollapsed: (collapsed: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Navbar: React.FC<NavbarProps> = ({ isCollapsed, setIsCollapsed }) => {
|
|
||||||
return (
|
|
||||||
<nav className={`bg-gray-800 text-white fixed inset-y-0 left-0 z-10 ${isCollapsed ? 'w-20' : 'w-64'} transition-all duration-300 flex flex-col items-center`}>
|
|
||||||
<div className="text-xl font-bold mt-5 mb-4">
|
|
||||||
AOUN
|
|
||||||
</div>
|
|
||||||
<button onClick={() => setIsCollapsed(!isCollapsed)} className="text-lg p-2">
|
|
||||||
{isCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
|
||||||
</button>
|
|
||||||
<ul className={`flex flex-col space-y-2 w-full p-4 ${isCollapsed ? 'items-center' : 'items-start'}`}>
|
|
||||||
<li className="w-full">
|
|
||||||
<Link href="/home" className={`hover:text-gray-300 flex ${isCollapsed ? 'justify-center' : 'justify-start'}`}>
|
|
||||||
{isCollapsed ? <HomeOutlined /> : '首页'}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li className="w-full">
|
|
||||||
<Link href="/management/permission" className={`hover:text-gray-300 flex ${isCollapsed ? 'justify-center' : 'justify-start'}`}>
|
|
||||||
{isCollapsed ? <LockOutlined /> : '权限管理'}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
<li className="w-full">
|
|
||||||
<Link href="/management/role" className={`hover:text-gray-300 flex ${isCollapsed ? 'justify-center' : 'justify-start'}`}>
|
|
||||||
{isCollapsed ? <UserOutlined /> : '角色管理'}
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Navbar;
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/**
|
|
||||||
* 性能监控组件
|
|
||||||
* 作者: 阿瑞
|
|
||||||
* 功能: 监控组件渲染性能,开发环境下显示性能指标
|
|
||||||
* 版本: v1.0
|
|
||||||
*/
|
|
||||||
import React, { useEffect, useRef } from 'react';
|
|
||||||
|
|
||||||
interface PerformanceMonitorProps {
|
|
||||||
componentName: string;
|
|
||||||
children: React.ReactNode;
|
|
||||||
enableLogging?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PerformanceMonitor: React.FC<PerformanceMonitorProps> = ({
|
|
||||||
componentName,
|
|
||||||
children,
|
|
||||||
enableLogging = process.env.NODE_ENV === 'development'
|
|
||||||
}) => {
|
|
||||||
const renderStartTime = useRef<number>(0);
|
|
||||||
const renderCount = useRef<number>(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!enableLogging) return;
|
|
||||||
|
|
||||||
renderCount.current += 1;
|
|
||||||
const renderEndTime = performance.now();
|
|
||||||
const renderDuration = renderEndTime - renderStartTime.current;
|
|
||||||
|
|
||||||
// 记录渲染性能
|
|
||||||
if (renderDuration > 100) {
|
|
||||||
console.warn(`⚠️ ${componentName} 渲染耗时过长: ${renderDuration.toFixed(2)}ms`);
|
|
||||||
} else if (renderDuration > 50) {
|
|
||||||
console.log(`⚡ ${componentName} 渲染耗时: ${renderDuration.toFixed(2)}ms`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记录渲染次数
|
|
||||||
if (renderCount.current > 10) {
|
|
||||||
console.log(`🔄 ${componentName} 已渲染 ${renderCount.current} 次`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 记录渲染开始时间
|
|
||||||
if (enableLogging) {
|
|
||||||
renderStartTime.current = performance.now();
|
|
||||||
}
|
|
||||||
|
|
||||||
return <>{children}</>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(PerformanceMonitor);
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
* @updated 使用原生fetch替代axios,符合项目技术规范
|
* @updated 使用原生fetch替代axios,符合项目技术规范
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
import React, { useState, useCallback, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
@@ -20,9 +20,8 @@ import {
|
|||||||
Col,
|
Col,
|
||||||
Modal,
|
Modal,
|
||||||
Tabs,
|
Tabs,
|
||||||
Skeleton,
|
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { useUserInfo } from '@/store/userStore';
|
import { useFullUserInfo } from '@/store/userStore';
|
||||||
import {
|
import {
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
MailOutlined,
|
MailOutlined,
|
||||||
@@ -30,6 +29,8 @@ import {
|
|||||||
UserOutlined,
|
UserOutlined,
|
||||||
TeamOutlined,
|
TeamOutlined,
|
||||||
IdcardOutlined,
|
IdcardOutlined,
|
||||||
|
NotificationOutlined,
|
||||||
|
ReloadOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { PageHeader } from '@ant-design/pro-components';
|
import { PageHeader } from '@ant-design/pro-components';
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ interface IUser {
|
|||||||
头像?: string;
|
头像?: string;
|
||||||
unionid?: string;
|
unionid?: string;
|
||||||
openid?: string;
|
openid?: string;
|
||||||
|
bark密钥?: string; // 添加bark密钥字段
|
||||||
角色?: {
|
角色?: {
|
||||||
名称: string;
|
名称: string;
|
||||||
描述: string;
|
描述: string;
|
||||||
@@ -60,50 +62,35 @@ interface IUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PersonalInfo: React.FC = () => {
|
const PersonalInfo: React.FC = () => {
|
||||||
const userInfo = useUserInfo(); // 从store获取用户信息
|
const { userInfo: userData, refreshUserInfo, hasCompleteInfo, hasRoleHomePage } = useFullUserInfo(); // 使用新的完整用户信息hook
|
||||||
const [form] = Form.useForm<IUser>();
|
const [form] = Form.useForm<IUser>();
|
||||||
const [loading, setLoading] = useState<boolean>(false);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
const [userData, setUserData] = useState<IUser | null>(null); // 保存用户数据
|
const [refreshLoading, setRefreshLoading] = useState<boolean>(false);
|
||||||
const [editModalVisible, setEditModalVisible] = useState<boolean>(false);
|
const [editModalVisible, setEditModalVisible] = useState<boolean>(false);
|
||||||
const userId = userInfo._id;
|
|
||||||
|
|
||||||
// 获取用户信息的函数,使用 useCallback 优化性能
|
|
||||||
const fetchUserInfo = useCallback(async () => {
|
|
||||||
if (!userId) return;
|
|
||||||
|
|
||||||
|
// 手动刷新个人信息的函数
|
||||||
|
const handleRefreshUserInfo = useCallback(async () => {
|
||||||
|
setRefreshLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/backstage/mine/info/${userId}`, {
|
await refreshUserInfo();
|
||||||
method: 'GET',
|
message.success('个人信息刷新成功');
|
||||||
headers: {
|
// 更新表单数据
|
||||||
'Content-Type': 'application/json',
|
form.setFieldsValue(userData);
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('获取个人信息失败');
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
setUserData(data);
|
|
||||||
form.setFieldsValue(data);
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error(error.message || '获取个人信息失败');
|
message.error('刷新个人信息失败');
|
||||||
|
} finally {
|
||||||
|
setRefreshLoading(false);
|
||||||
}
|
}
|
||||||
}, [userId, form]);
|
}, [refreshUserInfo, form, userData]);
|
||||||
|
|
||||||
// 模块级注释:组件初始化时获取用户信息
|
|
||||||
useEffect(() => {
|
|
||||||
fetchUserInfo();
|
|
||||||
}, [fetchUserInfo]);
|
|
||||||
|
|
||||||
// 更新个人信息的处理函数
|
// 更新个人信息的处理函数
|
||||||
const onFinish = async (values: IUser) => {
|
const onFinish = async (values: IUser) => {
|
||||||
if (!userId) return;
|
if (!userData?._id) return;
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/backstage/mine/info/${userId}`, {
|
const response = await fetch(`/api/backstage/mine/info/${userData._id}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -118,7 +105,7 @@ const PersonalInfo: React.FC = () => {
|
|||||||
|
|
||||||
message.success('更新成功');
|
message.success('更新成功');
|
||||||
setEditModalVisible(false);
|
setEditModalVisible(false);
|
||||||
await fetchUserInfo(); // 更新信息后重新获取
|
await handleRefreshUserInfo(); // 更新信息后重新获取
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
message.error(error.message || '更新失败');
|
message.error(error.message || '更新失败');
|
||||||
} finally {
|
} finally {
|
||||||
@@ -132,10 +119,10 @@ const PersonalInfo: React.FC = () => {
|
|||||||
return userData.角色.权限.map((item) => ({
|
return userData.角色.权限.map((item) => ({
|
||||||
title: item.名称,
|
title: item.名称,
|
||||||
key: item._id,
|
key: item._id,
|
||||||
children: item.子级.map((child) => ({
|
children: item.子级?.map((child) => ({
|
||||||
title: child.名称,
|
title: child.名称,
|
||||||
key: child._id,
|
key: child._id,
|
||||||
})),
|
})) || [],
|
||||||
}));
|
}));
|
||||||
}, [userData]);
|
}, [userData]);
|
||||||
|
|
||||||
@@ -143,55 +130,134 @@ const PersonalInfo: React.FC = () => {
|
|||||||
<div>
|
<div>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="个人信息"
|
title="个人信息"
|
||||||
subTitle="查看和更新您的个人信息"
|
subTitle={
|
||||||
|
hasCompleteInfo && hasRoleHomePage
|
||||||
|
? "查看和更新您的个人信息"
|
||||||
|
: !hasCompleteInfo
|
||||||
|
? "⚠️ 个人信息不完整,请及时更新"
|
||||||
|
: "⚠️ 角色主页路径缺失,请联系管理员配置"
|
||||||
|
}
|
||||||
extra={[
|
extra={[
|
||||||
<Button key="edit" type="primary" icon={<EditOutlined />} onClick={() => setEditModalVisible(true)}>
|
<Button
|
||||||
|
key="refresh"
|
||||||
|
icon={<ReloadOutlined />}
|
||||||
|
onClick={handleRefreshUserInfo}
|
||||||
|
loading={refreshLoading}
|
||||||
|
style={{ marginRight: 8 }}
|
||||||
|
>
|
||||||
|
刷新
|
||||||
|
</Button>,
|
||||||
|
<Button
|
||||||
|
key="edit"
|
||||||
|
type="primary"
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
setEditModalVisible(true);
|
||||||
|
form.setFieldsValue(userData); // 打开模态框时设置表单数据
|
||||||
|
}}
|
||||||
|
>
|
||||||
编辑信息
|
编辑信息
|
||||||
</Button>,
|
</Button>,
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<Card style={{ marginBottom: 24 }}>
|
|
||||||
{userData ? (
|
|
||||||
<Row gutter={24}>
|
<Row gutter={24}>
|
||||||
<Col xs={24} sm={24} md={8} lg={6} style={{ textAlign: 'center' }}>
|
{/* 左侧用户信息卡片 */}
|
||||||
|
<Col xs={24} sm={24} md={8} lg={8} xl={6}>
|
||||||
|
<Card style={{ marginBottom: 24 }}>
|
||||||
|
{userData && userData._id ? (
|
||||||
|
<div style={{ textAlign: 'center' }}>
|
||||||
<Avatar size={120} src={userData?.头像} icon={<UserOutlined />} />
|
<Avatar size={120} src={userData?.头像} icon={<UserOutlined />} />
|
||||||
<h2 style={{ marginTop: 16 }}>{userData?.姓名}</h2>
|
<h2 style={{ marginTop: 16, marginBottom: 8 }}>{userData?.姓名}</h2>
|
||||||
<p>{userData?.微信昵称}</p>
|
<p style={{ color: '#666', marginBottom: 16 }}>{userData?.微信昵称 || '未设置'}</p>
|
||||||
</Col>
|
|
||||||
<Col xs={24} sm={24} md={16} lg={18}>
|
<Descriptions column={1} size="small">
|
||||||
<Descriptions title="基本信息" column={1} bordered>
|
<Descriptions.Item label={<MailOutlined />}>{userData?.邮箱}</Descriptions.Item>
|
||||||
<Descriptions.Item label={<MailOutlined />}> {userData?.邮箱}</Descriptions.Item>
|
<Descriptions.Item label={<PhoneOutlined />}>{userData?.电话}</Descriptions.Item>
|
||||||
<Descriptions.Item label={<PhoneOutlined />}> {userData?.电话}</Descriptions.Item>
|
<Descriptions.Item label={<TeamOutlined />}>{userData?.团队?.名称 || '未分配'}</Descriptions.Item>
|
||||||
<Descriptions.Item label={<TeamOutlined />}> {userData?.团队?.名称}</Descriptions.Item>
|
<Descriptions.Item label={<IdcardOutlined />}>{userData?.角色?.名称 || '未设置'}</Descriptions.Item>
|
||||||
<Descriptions.Item label={<IdcardOutlined />}> {userData?.角色?.名称}</Descriptions.Item>
|
<Descriptions.Item label={
|
||||||
</Descriptions>
|
<span>
|
||||||
</Col>
|
<NotificationOutlined style={{ marginRight: 4 }} />
|
||||||
</Row>
|
Bark推送
|
||||||
|
</span>
|
||||||
|
}>
|
||||||
|
{userData?.bark密钥 ? (
|
||||||
|
<span style={{ color: '#52c41a' }}>✅ 已配置</span>
|
||||||
) : (
|
) : (
|
||||||
<Skeleton active />
|
<span style={{ color: '#ff4d4f' }}>❌ 未配置</span>
|
||||||
|
)}
|
||||||
|
</Descriptions.Item>
|
||||||
|
</Descriptions>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div style={{ textAlign: 'center', padding: '40px 20px' }}>
|
||||||
|
<UserOutlined style={{ fontSize: 48, color: '#ccc', marginBottom: 16 }} />
|
||||||
|
<p>请先登录以查看个人信息</p>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
{/* 右侧详细信息 */}
|
||||||
|
<Col xs={24} sm={24} md={16} lg={16} xl={18}>
|
||||||
<Card>
|
<Card>
|
||||||
<Tabs defaultActiveKey="1">
|
<Tabs defaultActiveKey="1">
|
||||||
<TabPane tab="团队与角色信息" key="1">
|
<TabPane tab="团队与角色信息" key="1">
|
||||||
<Descriptions column={1} bordered>
|
<Descriptions title="详细信息" column={2} bordered>
|
||||||
<Descriptions.Item label="团队名称">{userData?.团队?.名称}</Descriptions.Item>
|
<Descriptions.Item label="团队名称" span={2}>{userData?.团队?.名称}</Descriptions.Item>
|
||||||
<Descriptions.Item label="团队拥有者">{userData?.团队?.拥有者?.姓名}</Descriptions.Item>
|
<Descriptions.Item label="团队拥有者">{userData?.团队?.拥有者?.姓名}</Descriptions.Item>
|
||||||
<Descriptions.Item label="角色名称">{userData?.角色?.名称}</Descriptions.Item>
|
<Descriptions.Item label="角色名称">{userData?.角色?.名称}</Descriptions.Item>
|
||||||
<Descriptions.Item label="角色描述">{userData?.角色?.描述}</Descriptions.Item>
|
<Descriptions.Item label="角色描述" span={2}>{userData?.角色?.描述}</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="主页路径" span={2}>
|
||||||
|
<code style={{ backgroundColor: '#f5f5f5', padding: '4px 8px', borderRadius: '4px' }}>
|
||||||
|
{userData?.角色?.主页 || '未设置'}
|
||||||
|
</code>
|
||||||
|
</Descriptions.Item>
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
<TabPane tab="权限列表" key="2">
|
<TabPane tab="推送配置" key="2">
|
||||||
|
<Descriptions title="Bark推送配置" column={2} bordered>
|
||||||
|
<Descriptions.Item label="推送状态">
|
||||||
|
{userData?.bark密钥 ? (
|
||||||
|
<span style={{ color: '#52c41a' }}>✅ 已配置</span>
|
||||||
|
) : (
|
||||||
|
<span style={{ color: '#ff4d4f' }}>❌ 未配置</span>
|
||||||
|
)}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="设备密钥">
|
||||||
|
{userData?.bark密钥 ? (
|
||||||
|
<code style={{ backgroundColor: '#f5f5f5', padding: '4px 8px', borderRadius: '4px' }}>
|
||||||
|
{userData.bark密钥.substring(0, 8)}...{userData.bark密钥.substring(userData.bark密钥.length - 8)}
|
||||||
|
</code>
|
||||||
|
) : (
|
||||||
|
<span style={{ color: '#999' }}>未设置</span>
|
||||||
|
)}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label="配置说明" span={2}>
|
||||||
|
<div>
|
||||||
|
<p style={{ margin: '4px 0' }}>• 在App Store下载并安装"Bark"应用</p>
|
||||||
|
<p style={{ margin: '4px 0' }}>• 打开应用,复制设备密钥</p>
|
||||||
|
<p style={{ margin: '4px 0' }}>• 在个人信息编辑中填入密钥即可接收推送通知</p>
|
||||||
|
</div>
|
||||||
|
</Descriptions.Item>
|
||||||
|
</Descriptions>
|
||||||
|
</TabPane>
|
||||||
|
<TabPane tab="权限列表" key="3">
|
||||||
|
<div style={{ padding: '16px 0' }}>
|
||||||
|
<h4 style={{ marginBottom: 16 }}>我的权限</h4>
|
||||||
<Tree
|
<Tree
|
||||||
treeData={permissionsTreeData}
|
treeData={permissionsTreeData}
|
||||||
//defaultExpandAll//默认展开所有节点
|
//defaultExpandAll//默认展开所有节点
|
||||||
//默认收起所有节点
|
//默认收起所有节点
|
||||||
defaultExpandParent={false}
|
defaultExpandParent={false}
|
||||||
|
showLine={{ showLeafIcon: false }}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</TabPane>
|
</TabPane>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Card>
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
{/* 编辑信息的 Modal */}
|
{/* 编辑信息的 Modal */}
|
||||||
<Modal
|
<Modal
|
||||||
@@ -200,27 +266,70 @@ const PersonalInfo: React.FC = () => {
|
|||||||
onCancel={() => setEditModalVisible(false)}
|
onCancel={() => setEditModalVisible(false)}
|
||||||
footer={null}
|
footer={null}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
|
width="80%"
|
||||||
>
|
>
|
||||||
<Form form={form} onFinish={onFinish} layout="vertical">
|
<Form form={form} onFinish={onFinish} layout="vertical">
|
||||||
<Form.Item name="微信昵称" label="微信昵称">
|
<Row gutter={24}>
|
||||||
<Input />
|
{/* 左侧基本信息 */}
|
||||||
</Form.Item>
|
<Col xs={24} sm={24} md={12} lg={12}>
|
||||||
|
<h4 style={{ marginBottom: 16, color: '#1890ff' }}>基本信息</h4>
|
||||||
<Form.Item name="姓名" label="姓名" rules={[{ required: true, message: '请输入姓名' }]}>
|
<Form.Item name="姓名" label="姓名" rules={[{ required: true, message: '请输入姓名' }]}>
|
||||||
<Input />
|
<Input placeholder="请输入姓名" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="电话" label="电话" rules={[{ required: true, message: '请输入电话' }]}>
|
<Form.Item name="电话" label="电话" rules={[{ required: true, message: '请输入电话' }]}>
|
||||||
<Input />
|
<Input placeholder="请输入电话" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="邮箱" label="邮箱" rules={[{ required: true, message: '请输入邮箱' }]}>
|
<Form.Item name="邮箱" label="邮箱" rules={[{ required: true, message: '请输入邮箱' }]}>
|
||||||
<Input />
|
<Input placeholder="请输入邮箱" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item style={{ textAlign: 'right' }}>
|
</Col>
|
||||||
|
|
||||||
|
{/* 右侧扩展信息 */}
|
||||||
|
<Col xs={24} sm={24} md={12} lg={12}>
|
||||||
|
<h4 style={{ marginBottom: 16, color: '#1890ff' }}>扩展配置</h4>
|
||||||
|
<Form.Item name="微信昵称" label="微信昵称">
|
||||||
|
<Input placeholder="请输入微信昵称" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="bark密钥"
|
||||||
|
label={
|
||||||
|
<span>
|
||||||
|
<NotificationOutlined style={{ marginRight: 4 }} />
|
||||||
|
Bark推送密钥
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
extra="从Bark应用中获取的设备密钥,用于接收系统推送通知"
|
||||||
|
>
|
||||||
|
<Input.Password
|
||||||
|
placeholder="请输入Bark设备密钥"
|
||||||
|
visibilityToggle={{
|
||||||
|
visible: false,
|
||||||
|
onVisibleChange: () => {},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
<Form.Item style={{ textAlign: 'right', marginTop: 24, marginBottom: 0 }}>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
|
<Button
|
||||||
|
icon={<ReloadOutlined />}
|
||||||
|
onClick={handleRefreshUserInfo}
|
||||||
|
loading={refreshLoading}
|
||||||
|
style={{ marginRight: 'auto' }}
|
||||||
|
>
|
||||||
|
刷新信息
|
||||||
|
</Button>
|
||||||
|
<div>
|
||||||
<Button onClick={() => setEditModalVisible(false)} style={{ marginRight: 8 }}>
|
<Button onClick={() => setEditModalVisible(false)} style={{ marginRight: 8 }}>
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="primary" htmlType="submit" loading={loading}>
|
<Button type="primary" htmlType="submit" loading={loading}>
|
||||||
更新信息
|
更新信息
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
// src/components/layout/_defaultProps.tsx
|
|
||||||
import { MenuDataItem } from '@ant-design/pro-components';
|
|
||||||
import { Icon } from '@iconify/react';
|
|
||||||
|
|
||||||
// 假设这个函数从外部传入,用于根据用户权限生成菜单
|
|
||||||
export const generateDynamicRoutes = (permissions: any[]): MenuDataItem[] => {
|
|
||||||
//打印权限,输出为数组
|
|
||||||
//console.log("permissions",permissions);
|
|
||||||
return permissions.map(permission => ({
|
|
||||||
path: permission.路径,
|
|
||||||
name: permission.名称,
|
|
||||||
icon: <Icon icon={permission.Icon} width="24" height="24" />,
|
|
||||||
component: './DynamicComponent', // 这里应指向实际组件路径
|
|
||||||
routes: permission.子级 && generateDynamicRoutes(permission.子级)
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
route: {
|
|
||||||
path: '/',
|
|
||||||
routes: [], // 初始化时不包含任何静态路由
|
|
||||||
},
|
|
||||||
location: {
|
|
||||||
pathname: '/',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
152
src/components/layout/_defaultProps.tsx.bak
Normal file
152
src/components/layout/_defaultProps.tsx.bak
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import {
|
||||||
|
ChromeFilled,
|
||||||
|
CrownFilled,
|
||||||
|
SmileFilled,
|
||||||
|
TabletFilled,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
route: {
|
||||||
|
path: '/',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/welcome',
|
||||||
|
name: '欢迎',
|
||||||
|
icon: <SmileFilled />,
|
||||||
|
component: './Welcome',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/admin',
|
||||||
|
name: '管理端',
|
||||||
|
icon: <CrownFilled />,
|
||||||
|
access: 'canAdmin',
|
||||||
|
component: './Admin',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/admin/sub-page1',
|
||||||
|
name: '一级页面',
|
||||||
|
icon: 'https://gw.alipayobjects.com/zos/antfincdn/upvrAjAPQX/Logo_Tech%252520UI.svg',
|
||||||
|
component: './Welcome',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/admin/sub-page2',
|
||||||
|
name: '二级页面',
|
||||||
|
icon: <CrownFilled />,
|
||||||
|
component: './Welcome',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/admin/sub-page3',
|
||||||
|
name: '三级页面',
|
||||||
|
icon: <CrownFilled />,
|
||||||
|
component: './Welcome',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '用户端',
|
||||||
|
icon: <TabletFilled />,
|
||||||
|
path: '/list',
|
||||||
|
component: './ListTableList',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/list/sub-page',
|
||||||
|
name: '列表页面',
|
||||||
|
icon: <CrownFilled />,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: 'sub-sub-page1',
|
||||||
|
name: '一一级列表页面',
|
||||||
|
icon: <CrownFilled />,
|
||||||
|
component: './Welcome',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'sub-sub-page2',
|
||||||
|
name: '一二级列表页面',
|
||||||
|
icon: <CrownFilled />,
|
||||||
|
component: './Welcome',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'sub-sub-page3',
|
||||||
|
name: '一三级列表页面',
|
||||||
|
icon: <CrownFilled />,
|
||||||
|
component: './Welcome',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/sub-page2',
|
||||||
|
name: '二级列表页面',
|
||||||
|
icon: <CrownFilled />,
|
||||||
|
component: './Welcome',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/list/sub-page3',
|
||||||
|
name: '三级列表页面',
|
||||||
|
icon: <CrownFilled />,
|
||||||
|
component: './Welcome',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'https://ant.design',
|
||||||
|
name: 'Ant Design 官网外链',
|
||||||
|
icon: <ChromeFilled />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
location: {
|
||||||
|
pathname: '/',
|
||||||
|
},
|
||||||
|
appList: [
|
||||||
|
{
|
||||||
|
icon: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
|
||||||
|
title: 'Ant Design',
|
||||||
|
desc: '杭州市较知名的 UI 设计语言',
|
||||||
|
url: 'https://ant.design',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',
|
||||||
|
title: 'AntV',
|
||||||
|
desc: '蚂蚁集团全新一代数据可视化解决方案',
|
||||||
|
url: 'https://antv.vision/',
|
||||||
|
target: '_blank',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'https://gw.alipayobjects.com/zos/antfincdn/upvrAjAPQX/Logo_Tech%252520UI.svg',
|
||||||
|
title: 'Pro Components',
|
||||||
|
desc: '专业级 UI 组件库',
|
||||||
|
url: 'https://procomponents.ant.design/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'https://img.alicdn.com/tfs/TB1zomHwxv1gK0jSZFFXXb0sXXa-200-200.png',
|
||||||
|
title: 'umi',
|
||||||
|
desc: '插件化的企业级前端应用框架。',
|
||||||
|
url: 'https://umijs.org/zh-CN/docs',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
icon: 'https://gw.alipayobjects.com/zos/bmw-prod/8a74c1d3-16f3-4719-be63-15e467a68a24/km0cv8vn_w500_h500.png',
|
||||||
|
title: 'qiankun',
|
||||||
|
desc: '可能是你见过最完善的微前端解决方案🧐',
|
||||||
|
url: 'https://qiankun.umijs.org/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'https://gw.alipayobjects.com/zos/rmsportal/XuVpGqBFxXplzvLjJBZB.svg',
|
||||||
|
title: '语雀',
|
||||||
|
desc: '知识创作与分享工具',
|
||||||
|
url: 'https://www.yuque.com/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'https://gw.alipayobjects.com/zos/rmsportal/LFooOLwmxGLsltmUjTAP.svg',
|
||||||
|
title: 'Kitchen ',
|
||||||
|
desc: 'Sketch 工具集',
|
||||||
|
url: 'https://kitchen.alipay.com/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'https://gw.alipayobjects.com/zos/bmw-prod/d3e3eb39-1cd7-4aa5-827c-877deced6b7e/lalxt4g3_w256_h256.png',
|
||||||
|
title: 'dumi',
|
||||||
|
desc: '为组件开发场景而生的文档工具',
|
||||||
|
url: 'https://d.umijs.org/zh-CN',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
/**
|
|
||||||
* Layout布局配置文件
|
|
||||||
* 作者: 阿瑞
|
|
||||||
* 功能: 集中管理Layout组件的配置项和常量
|
|
||||||
* 版本: v1.0
|
|
||||||
*/
|
|
||||||
import { type ProSettings } from '@ant-design/pro-components';
|
|
||||||
|
|
||||||
// 默认头像配置
|
|
||||||
export const DEFAULT_AVATAR = {
|
|
||||||
src: 'https://gw.alipayobjects.com/zos/antfincdn/efFD$IOql2/weixintupian_20170331104822.jpg',
|
|
||||||
size: 'small' as const,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 默认路由配置
|
|
||||||
export const DEFAULT_PROPS = {
|
|
||||||
route: {
|
|
||||||
path: '/',
|
|
||||||
routes: [],
|
|
||||||
},
|
|
||||||
location: {
|
|
||||||
pathname: '/',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// ProLayout基础设置
|
|
||||||
export const getLayoutSettings = (navTheme: string, colorPrimary: string): Partial<ProSettings> => ({
|
|
||||||
fixSiderbar: true,
|
|
||||||
layout: "mix",
|
|
||||||
splitMenus: false,
|
|
||||||
navTheme: navTheme as any,
|
|
||||||
contentWidth: "Fluid",
|
|
||||||
colorPrimary,
|
|
||||||
title: "私域管理系统V3",
|
|
||||||
siderMenuType: "sub",
|
|
||||||
fixedHeader: true,
|
|
||||||
menuHeaderRender: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 菜单配置
|
|
||||||
export const MENU_CONFIG = {
|
|
||||||
collapsedShowGroupTitle: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 内容样式配置
|
|
||||||
export const getContentStyle = (navTheme: string) => ({
|
|
||||||
backgroundColor: navTheme === 'light' ? '#fff' : '',
|
|
||||||
height: '100%',
|
|
||||||
width: '100%',
|
|
||||||
});
|
|
||||||
|
|
||||||
// 模态框配置
|
|
||||||
export const MODAL_CONFIG = {
|
|
||||||
personalInfo: {
|
|
||||||
title: "个人资料",
|
|
||||||
width: 800,
|
|
||||||
destroyOnClose: true,
|
|
||||||
},
|
|
||||||
mySales: {
|
|
||||||
title: "我的业绩",
|
|
||||||
width: 800,
|
|
||||||
destroyOnClose: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// 性能优化配置
|
|
||||||
export const PERFORMANCE_CONFIG = {
|
|
||||||
enableMonitoring: process.env.NODE_ENV === 'development',
|
|
||||||
renderThreshold: 50, // 渲染时间阈值(ms)
|
|
||||||
warningThreshold: 100, // 警告阈值(ms)
|
|
||||||
};
|
|
||||||
|
|
||||||
// 主题配置
|
|
||||||
export const THEME_CONFIG = {
|
|
||||||
storageKey: 'navTheme',
|
|
||||||
colorStorageKey: 'colorPrimary',
|
|
||||||
defaultTheme: 'light' as const,
|
|
||||||
defaultColor: '#1677FF',
|
|
||||||
};
|
|
||||||
@@ -13,6 +13,7 @@ const UserSchema: Schema = new Schema({
|
|||||||
头像: { type: String }, // 用户头像字段
|
头像: { type: String }, // 用户头像字段
|
||||||
unionid: { type: String, unique: true, sparse: true }, // 添加sparse以允许null值
|
unionid: { type: String, unique: true, sparse: true }, // 添加sparse以允许null值
|
||||||
openid: { type: String, unique: true, sparse: true }, // 添加openid字段,sparse允许null值
|
openid: { type: String, unique: true, sparse: true }, // 添加openid字段,sparse允许null值
|
||||||
|
bark密钥: { type: String }, // Bark推送设备密钥,用于iOS推送通知
|
||||||
}, { timestamps: true }); // 自动添加创建时间和更新时间
|
}, { timestamps: true }); // 自动添加创建时间和更新时间
|
||||||
UserSchema.index({ 团队: 1 }); // 对团队字段建立索引
|
UserSchema.index({ 团队: 1 }); // 对团队字段建立索引
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ export interface IUser {
|
|||||||
头像?: string;
|
头像?: string;
|
||||||
unionid?: string;
|
unionid?: string;
|
||||||
openid?: string;
|
openid?: string;
|
||||||
|
bark密钥?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义团队接口类型
|
// 定义团队接口类型
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { NextApiRequest, NextApiResponse } from 'next';
|
import { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { broadcastUpdate } from './sse'; // 引入广播功能
|
|
||||||
import { Account } from '@/models';
|
import { Account } from '@/models';
|
||||||
import connectDB from '@/lib/connectDB';
|
import connectDB from '@/lib/connectDB';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@@ -69,9 +68,6 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
|
|
||||||
await account.save();
|
await account.save();
|
||||||
|
|
||||||
// 广播更新
|
|
||||||
broadcastUpdate(account.团队);
|
|
||||||
|
|
||||||
res.status(200).json({ success: true });
|
res.status(200).json({ success: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存增长记录失败:', error);
|
console.error('保存增长记录失败:', error);
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
//src\pages\api\backstage\accounts\accountgrowth\sse.ts
|
|
||||||
import { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
import { Account } from '@/models';
|
|
||||||
|
|
||||||
let clients: NextApiResponse[] = [];
|
|
||||||
|
|
||||||
const handler = (req: NextApiRequest, res: NextApiResponse) => {
|
|
||||||
const { teamId } = req.query;
|
|
||||||
|
|
||||||
// 设置 SSE 头
|
|
||||||
res.setHeader('Content-Type', 'text/event-stream');
|
|
||||||
res.setHeader('Cache-Control', 'no-cache');
|
|
||||||
res.setHeader('Connection', 'keep-alive');
|
|
||||||
|
|
||||||
// 添加客户端
|
|
||||||
clients.push(res);
|
|
||||||
|
|
||||||
// 监听连接关闭事件,移除客户端
|
|
||||||
req.on('close', () => {
|
|
||||||
clients = clients.filter(client => client !== res);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 每次新连接时发送当前数据
|
|
||||||
Account.find({ 团队: teamId }).select('_id 账号编号 微信号 日增长数据').then((accounts) => {
|
|
||||||
res.write(`data: ${JSON.stringify({ accounts })}\n\n`);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 广播更新
|
|
||||||
export const broadcastUpdate = (teamId: string) => {
|
|
||||||
Account.find({ 团队: teamId }).select('_id 账号编号 微信号 日增长数据').then((accounts) => {
|
|
||||||
clients.forEach((client) => {
|
|
||||||
client.write(`data: ${JSON.stringify({ accounts })}\n\n`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default handler;
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
import { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
import { Account } from '@/models';
|
|
||||||
|
|
||||||
let clients: NextApiResponse[] = [];
|
|
||||||
|
|
||||||
const handler = (req: NextApiRequest, res: NextApiResponse) => {
|
|
||||||
const { teamId } = req.query;
|
|
||||||
|
|
||||||
// 设置 SSE 头
|
|
||||||
res.setHeader('Content-Type', 'text/event-stream');
|
|
||||||
res.setHeader('Cache-Control', 'no-cache');
|
|
||||||
res.setHeader('Connection', 'keep-alive');
|
|
||||||
|
|
||||||
// 添加客户端
|
|
||||||
clients.push(res);
|
|
||||||
|
|
||||||
// 监听连接关闭事件,移除客户端
|
|
||||||
req.on('close', () => {
|
|
||||||
clients = clients.filter(client => client !== res);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 每次新连接时发送当前数据
|
|
||||||
Account.find({ 团队: teamId }).select('_id 账号编号 微信号 日增长数据').then((accounts) => {
|
|
||||||
res.write(`data: ${JSON.stringify({ accounts })}\n\n`);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 广播更新
|
|
||||||
export const broadcastUpdate = (teamId: string) => {
|
|
||||||
Account.find({ 团队: teamId }).select('_id 账号编号 微信号 日增长数据').then((accounts) => {
|
|
||||||
clients.forEach((client) => {
|
|
||||||
client.write(`data: ${JSON.stringify({ accounts })}\n\n`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default handler;
|
|
||||||
@@ -28,7 +28,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
//关联角色
|
//关联角色
|
||||||
.populate({
|
.populate({
|
||||||
path: '角色',
|
path: '角色',
|
||||||
select: '名称 描述 权限',
|
select: '名称 描述 权限 主页', // 添加主页字段
|
||||||
populate: {
|
populate: {
|
||||||
path: '权限',
|
path: '权限',
|
||||||
populate: { path: '子级' },
|
populate: { path: '子级' },
|
||||||
@@ -59,6 +59,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
电话: user.电话,
|
电话: user.电话,
|
||||||
unionid: user.unionid,
|
unionid: user.unionid,
|
||||||
openid: user.openid,
|
openid: user.openid,
|
||||||
|
bark密钥: user.bark密钥, // 添加bark密钥字段
|
||||||
};
|
};
|
||||||
|
|
||||||
res.status(200).json(userInfo );
|
res.status(200).json(userInfo );
|
||||||
|
|||||||
@@ -50,13 +50,14 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
}
|
}
|
||||||
} else if (req.method === 'PUT') {
|
} else if (req.method === 'PUT') {
|
||||||
try {
|
try {
|
||||||
const { 客户, 产品, 成交日期, 应收金额, 收款金额, 待收款, 收款平台, 待收已收, 收款状态, 备注, 导购 } = req.body;
|
const { 客户, 产品, 订单来源, 成交日期, 应收金额, 收款金额, 待收款, 收款平台, 待收已收, 收款状态, 备注, 导购 } = req.body;
|
||||||
|
|
||||||
const updatedSalesRecord = await SalesRecord.findByIdAndUpdate(
|
const updatedSalesRecord = await SalesRecord.findByIdAndUpdate(
|
||||||
id,
|
id,
|
||||||
{
|
{
|
||||||
客户,
|
客户,
|
||||||
产品,
|
产品,
|
||||||
|
订单来源,
|
||||||
成交日期,
|
成交日期,
|
||||||
应收金额,
|
应收金额,
|
||||||
收款金额,
|
收款金额,
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
||||||
|
|
||||||
// 全局变量,用于存储剩余时间
|
|
||||||
let remainingTimeGlobal: number | null = null;
|
|
||||||
// 全局变量,用于存储计时器的 ID
|
|
||||||
let intervalIdGlobal: NodeJS.Timeout | null = null;
|
|
||||||
|
|
||||||
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
||||||
console.log("SSE 连接已打开");
|
|
||||||
|
|
||||||
// 设置响应头,指定为 SSE 流式传输
|
|
||||||
res.setHeader('Content-Type', 'text/event-stream');
|
|
||||||
res.setHeader('Cache-Control', 'no-cache');
|
|
||||||
res.setHeader('Connection', 'keep-alive');
|
|
||||||
res.flushHeaders(); // 立即刷新响应头
|
|
||||||
|
|
||||||
// 如果全局倒计时未开始,则初始化
|
|
||||||
if (remainingTimeGlobal === null) {
|
|
||||||
remainingTimeGlobal = 600; // 默认30秒倒计时
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送时间更新的函数
|
|
||||||
const sendTimeUpdate = () => {
|
|
||||||
if (remainingTimeGlobal !== null && remainingTimeGlobal >= 0) {
|
|
||||||
//console.log(`发送更新: ${remainingTimeGlobal}`);
|
|
||||||
res.write(`data: ${remainingTimeGlobal}\n\n`); // 发送剩余时间给客户端
|
|
||||||
remainingTimeGlobal -= 1;
|
|
||||||
} else {
|
|
||||||
// 当倒计时结束时清除计时器并关闭 SSE 连接
|
|
||||||
/*
|
|
||||||
if (intervalIdGlobal) clearInterval(intervalIdGlobal);
|
|
||||||
remainingTimeGlobal = null;
|
|
||||||
intervalIdGlobal = null;
|
|
||||||
console.log("SSE 连接已关闭(倒计时结束)");
|
|
||||||
res.end(); // 结束 SSE 响应*/
|
|
||||||
// 当倒计时结束时重置倒计时,并继续保持连接
|
|
||||||
remainingTimeGlobal = 600; // 重置倒计时时间
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 如果计时器未启动,则启动
|
|
||||||
if (!intervalIdGlobal) {
|
|
||||||
intervalIdGlobal = setInterval(sendTimeUpdate, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 立即发送当前的剩余时间
|
|
||||||
sendTimeUpdate();
|
|
||||||
|
|
||||||
req.on('close', () => {
|
|
||||||
console.log("SSE 连接已关闭(客户端断开连接)");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -35,6 +35,7 @@ export default connectDB(async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
_id: user._id,
|
_id: user._id,
|
||||||
姓名: user.姓名,
|
姓名: user.姓名,
|
||||||
邮箱: user.邮箱,
|
邮箱: user.邮箱,
|
||||||
|
电话: user.电话, // 添加电话字段
|
||||||
团队: user.团队, // 团队信息
|
团队: user.团队, // 团队信息
|
||||||
角色: {
|
角色: {
|
||||||
...user.角色.toObject(),
|
...user.角色.toObject(),
|
||||||
@@ -44,6 +45,7 @@ export default connectDB(async (req: NextApiRequest, res: NextApiResponse) => {
|
|||||||
头像: user.头像,
|
头像: user.头像,
|
||||||
unionid: user.unionid,
|
unionid: user.unionid,
|
||||||
openid: user.openid,
|
openid: user.openid,
|
||||||
|
bark密钥: user.bark密钥, // 添加bark密钥字段
|
||||||
};
|
};
|
||||||
|
|
||||||
// 返回用户信息
|
// 返回用户信息
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,51 +1,116 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
/**
|
||||||
import { Modal, Form, Input, Button, App } from 'antd';
|
* @file 发货信息管理模态框组件
|
||||||
import { ISalesRecord } from '@/models/types';
|
* @author 阿瑞
|
||||||
|
* @description 用于管理销售记录的发货信息,支持批量产品物流单号录入
|
||||||
|
* @version 1.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
const { useApp } = App;
|
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
||||||
|
import {
|
||||||
|
Modal,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
Button,
|
||||||
|
App,
|
||||||
|
Card,
|
||||||
|
Space,
|
||||||
|
Typography,
|
||||||
|
Divider,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Tag,
|
||||||
|
Avatar
|
||||||
|
} from 'antd';
|
||||||
|
import {
|
||||||
|
TruckOutlined,
|
||||||
|
UserOutlined,
|
||||||
|
ShoppingCartOutlined,
|
||||||
|
NumberOutlined,
|
||||||
|
CheckCircleOutlined
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import { ISalesRecord } from '@/models/types';
|
||||||
import { useUserInfo } from '@/store/userStore';
|
import { useUserInfo } from '@/store/userStore';
|
||||||
|
|
||||||
|
const { useApp } = App;
|
||||||
|
const { Title, Text } = Typography;
|
||||||
|
|
||||||
|
// 组件属性接口定义
|
||||||
interface ShipModalProps {
|
interface ShipModalProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
onOk: () => void;
|
onOk: () => void;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
record: ISalesRecord | null; // 传入的销售记录
|
record: ISalesRecord | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 物流单号映射接口
|
||||||
|
interface LogisticsNumbersMap {
|
||||||
|
[productId: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发货产品信息接口
|
||||||
|
interface ShippingProduct {
|
||||||
|
productId: string;
|
||||||
|
logisticsNumber: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发货信息管理模态框组件
|
||||||
|
* 提供现代化的发货信息录入界面,支持多产品物流单号管理
|
||||||
|
*/
|
||||||
const ShipModal: React.FC<ShipModalProps> = ({ visible, onOk, onCancel, record }) => {
|
const ShipModal: React.FC<ShipModalProps> = ({ visible, onOk, onCancel, record }) => {
|
||||||
|
// ==================== 状态管理 ====================
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [logisticsNumbers, setLogisticsNumbers] = useState<{ [key: string]: string }>({}); // 保存每个产品的物流单号
|
const [logisticsNumbers, setLogisticsNumbers] = useState<LogisticsNumbersMap>({});
|
||||||
const userInfo = useUserInfo(); // 获取当前用户信息
|
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
||||||
const { message } = useApp(); // 使用 useApp hook 获取 message 实例
|
|
||||||
|
|
||||||
useEffect(() => {
|
// ==================== Hooks ====================
|
||||||
if (record) {
|
const userInfo = useUserInfo();
|
||||||
// 清空表单
|
const { message } = useApp();
|
||||||
form.resetFields();
|
|
||||||
form.setFieldsValue({
|
|
||||||
客户尾号: record?.客户?.电话 ? record.客户.电话.slice(-4) : '', // 自动填入客户电话尾号
|
|
||||||
});
|
|
||||||
|
|
||||||
// 初始化物流单号状态
|
// ==================== 计算属性 ====================
|
||||||
const initialLogisticsNumbers: { [key: string]: string } = {};
|
// 客户电话尾号显示
|
||||||
record?.产品?.forEach(product => {
|
const customerPhoneTail = useMemo(() => {
|
||||||
initialLogisticsNumbers[product._id] = ''; // 初始化每个产品的物流单号为空
|
return record?.客户?.电话 ? record.客户.电话.slice(-4) : '';
|
||||||
});
|
}, [record?.客户?.电话]);
|
||||||
setLogisticsNumbers(initialLogisticsNumbers);
|
|
||||||
|
// 产品列表
|
||||||
|
const productList = useMemo(() => {
|
||||||
|
return record?.产品 || [];
|
||||||
|
}, [record?.产品]);
|
||||||
|
|
||||||
|
// 已填写物流单号的产品数量
|
||||||
|
const filledLogisticsCount = useMemo(() => {
|
||||||
|
return Object.values(logisticsNumbers).filter(number => number.trim()).length;
|
||||||
|
}, [logisticsNumbers]);
|
||||||
|
|
||||||
|
// ==================== 工具函数 ====================
|
||||||
|
/**
|
||||||
|
* 清理和格式化物流单号
|
||||||
|
* @param value 原始输入值
|
||||||
|
* @returns 清理后的物流单号
|
||||||
|
*/
|
||||||
|
const cleanLogisticsNumber = useCallback((value: string): string => {
|
||||||
|
return value.replace(/[\s.,/#!$%\^&\*;:{}=\-_`~()<>[\]'"|\\?@+]/g, '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取现有物流记录
|
||||||
|
* @param recordId 销售记录ID
|
||||||
|
*/
|
||||||
|
const fetchExistingLogistics = useCallback(async (recordId: string) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/tools/logistics?关联记录=${recordId}`);
|
||||||
|
|
||||||
// 获取已有的物流记录并填充单号
|
|
||||||
fetch(`/api/tools/logistics?关联记录=${record._id}`)
|
|
||||||
.then(async (response) => {
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`网络错误或服务器错误: ${response.status}`);
|
throw new Error(`网络错误: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const logisticsRecords = await response.json();
|
const logisticsRecords = await response.json();
|
||||||
|
|
||||||
// 处理返回的物流记录(可能是空数组)
|
|
||||||
if (logisticsRecords && Array.isArray(logisticsRecords) && logisticsRecords.length > 0) {
|
if (logisticsRecords && Array.isArray(logisticsRecords) && logisticsRecords.length > 0) {
|
||||||
const updatedLogisticsNumbers: { [key: string]: string } = { ...initialLogisticsNumbers };
|
const updatedLogisticsNumbers: LogisticsNumbersMap = {};
|
||||||
|
|
||||||
// 遍历物流记录,将已有的单号填充到对应的产品
|
// 填充已有的物流单号
|
||||||
logisticsRecords.forEach((logisticsRecord: any) => {
|
logisticsRecords.forEach((logisticsRecord: any) => {
|
||||||
const productId = logisticsRecord.产品?._id || logisticsRecord.产品;
|
const productId = logisticsRecord.产品?._id || logisticsRecord.产品;
|
||||||
if (productId && logisticsRecord.物流单号) {
|
if (productId && logisticsRecord.物流单号) {
|
||||||
@@ -53,32 +118,69 @@ const ShipModal: React.FC<ShipModalProps> = ({ visible, onOk, onCancel, record }
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setLogisticsNumbers(updatedLogisticsNumbers);
|
setLogisticsNumbers(prev => ({ ...prev, ...updatedLogisticsNumbers }));
|
||||||
console.log('已加载现有物流记录');
|
console.log('已加载现有物流记录');
|
||||||
} else {
|
} else {
|
||||||
// 没有物流记录是正常情况,不需要错误提示
|
|
||||||
console.log('暂无物流记录,将创建新记录');
|
console.log('暂无物流记录,将创建新记录');
|
||||||
}
|
}
|
||||||
})
|
} catch (error) {
|
||||||
.catch((err: unknown) => {
|
console.error('获取物流记录失败:', error);
|
||||||
console.error('获取物流记录失败:', err);
|
|
||||||
// 只在真正的网络错误时才提示用户
|
|
||||||
message.warning('获取现有物流记录失败,将创建新记录');
|
message.warning('获取现有物流记录失败,将创建新记录');
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [record, form]);
|
}, [message]);
|
||||||
|
|
||||||
const handleOk = async () => {
|
// ==================== 副作用处理 ====================
|
||||||
|
useEffect(() => {
|
||||||
|
if (record && visible) {
|
||||||
|
// 重置表单和状态
|
||||||
|
form.resetFields();
|
||||||
|
|
||||||
|
// 设置客户电话尾号
|
||||||
|
form.setFieldsValue({
|
||||||
|
客户尾号: customerPhoneTail,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化物流单号状态
|
||||||
|
const initialLogisticsNumbers: LogisticsNumbersMap = {};
|
||||||
|
productList.forEach(product => {
|
||||||
|
initialLogisticsNumbers[product._id] = '';
|
||||||
|
});
|
||||||
|
setLogisticsNumbers(initialLogisticsNumbers);
|
||||||
|
|
||||||
|
// 获取已有物流记录
|
||||||
|
if (record._id) {
|
||||||
|
fetchExistingLogistics(record._id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [record, visible, form, customerPhoneTail, productList, fetchExistingLogistics]);
|
||||||
|
|
||||||
|
// ==================== 事件处理器 ====================
|
||||||
|
/**
|
||||||
|
* 处理物流单号变更
|
||||||
|
*/
|
||||||
|
const handleLogisticsNumberChange = useCallback((productId: string, value: string) => {
|
||||||
|
const cleanedValue = cleanLogisticsNumber(value);
|
||||||
|
setLogisticsNumbers(prevState => ({
|
||||||
|
...prevState,
|
||||||
|
[productId]: cleanedValue
|
||||||
|
}));
|
||||||
|
}, [cleanLogisticsNumber]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理表单提交
|
||||||
|
*/
|
||||||
|
const handleSubmit = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
|
setIsSubmitting(true);
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
|
|
||||||
// 过滤出有物流单号的产品
|
// 过滤有效的物流信息
|
||||||
const productsWithLogisticsNumbers = (record?.产品 || []) // 确保 record?.产品 始终是数组
|
const productsWithLogisticsNumbers: ShippingProduct[] = productList
|
||||||
.map(product => ({
|
.map(product => ({
|
||||||
productId: product._id,
|
productId: product._id,
|
||||||
logisticsNumber: logisticsNumbers[product._id]
|
logisticsNumber: logisticsNumbers[product._id]?.trim() || ''
|
||||||
}))
|
}))
|
||||||
.filter(item => item.logisticsNumber); // 只保留填写了物流单号的产品
|
.filter(item => item.logisticsNumber);
|
||||||
|
|
||||||
if (productsWithLogisticsNumbers.length === 0) {
|
if (productsWithLogisticsNumbers.length === 0) {
|
||||||
message.error('请至少为一个产品填写物流单号');
|
message.error('请至少为一个产品填写物流单号');
|
||||||
@@ -89,8 +191,8 @@ const ShipModal: React.FC<ShipModalProps> = ({ visible, onOk, onCancel, record }
|
|||||||
...values,
|
...values,
|
||||||
团队: userInfo.团队?._id,
|
团队: userInfo.团队?._id,
|
||||||
关联记录: record?._id,
|
关联记录: record?._id,
|
||||||
类型: 'SalesRecord', // 确保类型为销售记录
|
类型: 'SalesRecord',
|
||||||
产品: productsWithLogisticsNumbers // 只提交填写了物流单号的产品
|
产品: productsWithLogisticsNumbers
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch('/api/tools/logistics', {
|
const response = await fetch('/api/tools/logistics', {
|
||||||
@@ -106,63 +208,168 @@ const ShipModal: React.FC<ShipModalProps> = ({ visible, onOk, onCancel, record }
|
|||||||
}
|
}
|
||||||
|
|
||||||
message.success('发货信息提交成功');
|
message.success('发货信息提交成功');
|
||||||
onOk(); // 关闭模态框
|
onOk();
|
||||||
} catch (error: unknown) {
|
} catch (error) {
|
||||||
console.error('发货信息提交失败:', error);
|
console.error('发货信息提交失败:', error);
|
||||||
message.error('发货信息提交失败');
|
message.error('发货信息提交失败');
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false);
|
||||||
}
|
}
|
||||||
};
|
}, [form, productList, logisticsNumbers, userInfo.团队?._id, record?._id, message, onOk]);
|
||||||
|
|
||||||
const handleLogisticsNumberChange = (productId: string, value: string) => {
|
|
||||||
setLogisticsNumbers(prevState => ({
|
|
||||||
...prevState,
|
|
||||||
[productId]: value // 更新每个产品的物流单号
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// ==================== 渲染组件 ====================
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
open={visible}
|
open={visible}
|
||||||
title="发货信息"
|
title={
|
||||||
|
<Space align="center" size="middle">
|
||||||
|
<TruckOutlined style={{ fontSize: '18px', color: '#1890ff' }} />
|
||||||
|
<Title level={4} style={{ margin: 0 }}>
|
||||||
|
发货信息管理
|
||||||
|
</Title>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
|
width={680}
|
||||||
|
styles={{
|
||||||
|
body: { padding: '24px' }
|
||||||
|
}}
|
||||||
footer={[
|
footer={[
|
||||||
<Button key="cancel" onClick={onCancel}>
|
<Button key="cancel" onClick={onCancel} size="large">
|
||||||
取消
|
取消
|
||||||
</Button>,
|
</Button>,
|
||||||
<Button key="submit" type="primary" onClick={handleOk}>
|
<Button
|
||||||
保存
|
key="submit"
|
||||||
|
type="primary"
|
||||||
|
onClick={handleSubmit}
|
||||||
|
loading={isSubmitting}
|
||||||
|
size="large"
|
||||||
|
icon={<CheckCircleOutlined />}
|
||||||
|
>
|
||||||
|
保存发货信息
|
||||||
</Button>,
|
</Button>,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Form form={form} layout="vertical">
|
<Form form={form} layout="vertical" size="large">
|
||||||
|
{/* 客户信息区域 */}
|
||||||
|
<Card
|
||||||
|
title={
|
||||||
|
<Space
|
||||||
|
style={{ marginTop: '16px' }}
|
||||||
|
align="center"
|
||||||
|
>
|
||||||
|
<Avatar icon={<UserOutlined />} style={{ backgroundColor: '#52c41a' }} />
|
||||||
|
<Text
|
||||||
|
style={{ fontSize: '16px', marginLeft: '8px' }}
|
||||||
|
strong>客户信息</Text>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
size="small"
|
||||||
|
style={{ marginBottom: '20px' }}
|
||||||
|
styles={{
|
||||||
|
body: { padding: '16px' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Row gutter={16}>
|
||||||
|
<Col span={12}>
|
||||||
|
<div style={{ marginTop: '8px' }}>
|
||||||
|
<Text type="secondary" style={{ fontSize: '14px' }}>客户姓名</Text>
|
||||||
|
<div style={{ marginTop: '8px' }}>
|
||||||
|
<Text strong style={{ fontSize: '16px' }}>
|
||||||
|
{record?.客户?.姓名 || '未知客户'}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="客户尾号"
|
name="客户尾号"
|
||||||
label="客户尾号"
|
label="客户电话尾号"
|
||||||
rules={[{ required: true, message: '请输入客户电话尾号' }]}
|
rules={[{ required: true, message: '客户电话尾号不能为空' }]}
|
||||||
>
|
|
||||||
<Input placeholder="自动填入客户电话尾号" disabled />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
{/* 动态生成每个产品的物流单号输入框 */}
|
|
||||||
{record?.产品?.map(product => (
|
|
||||||
<Form.Item
|
|
||||||
key={product._id}
|
|
||||||
label={`物流单号 (${product.名称})`}
|
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
placeholder={`请输入${product.名称}的物流单号`}
|
prefix={<NumberOutlined style={{ color: '#8c8c8c' }} />}
|
||||||
value={logisticsNumbers[product._id] || ''}
|
placeholder="自动填入"
|
||||||
//onChange={e => handleLogisticsNumberChange(product._id, e.target.value)}
|
disabled
|
||||||
onChange={e => {
|
style={{
|
||||||
const cleanedValue = e.target.value.replace(/[\s.,/#!$%\^&\*;:{}=\-_`~()<>[\]'"|\\?@+]/g, '');//过滤特殊字符和空格
|
backgroundColor: '#f5f5f5',
|
||||||
handleLogisticsNumberChange(product._id, cleanedValue);
|
color: '#262626'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Divider orientation="left" orientationMargin="0">
|
||||||
|
<Space align="center">
|
||||||
|
<ShoppingCartOutlined style={{ color: '#1890ff' }} />
|
||||||
|
<Text strong>产品物流信息</Text>
|
||||||
|
<Tag color={filledLogisticsCount > 0 ? 'success' : 'default'}>
|
||||||
|
{filledLogisticsCount}/{productList.length} 已填写
|
||||||
|
</Tag>
|
||||||
|
</Space>
|
||||||
|
</Divider>
|
||||||
|
|
||||||
|
{/* 产品物流信息区域 */}
|
||||||
|
<Row gutter={[16, 16]}>
|
||||||
|
{productList.map((product, index) => (
|
||||||
|
<Col span={24} key={product._id}>
|
||||||
|
<Card
|
||||||
|
size="small"
|
||||||
|
style={{
|
||||||
|
border: logisticsNumbers[product._id] ? '1px solid #52c41a' : '1px solid #d9d9d9',
|
||||||
|
backgroundColor: logisticsNumbers[product._id] ? '#f6ffed' : '#fafafa'
|
||||||
|
}}
|
||||||
|
styles={{
|
||||||
|
body: { padding: '16px' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Row gutter={16} align="middle">
|
||||||
|
<Col span={6}>
|
||||||
|
<Space direction="vertical" size="small">
|
||||||
|
<Text type="secondary" style={{ fontSize: '12px' }}>
|
||||||
|
产品 {index + 1}
|
||||||
|
</Text>
|
||||||
|
<Text strong style={{ fontSize: '14px' }}>
|
||||||
|
{product.名称}
|
||||||
|
</Text>
|
||||||
|
</Space>
|
||||||
|
</Col>
|
||||||
|
<Col span={18}>
|
||||||
|
<Form.Item
|
||||||
|
label={`物流单号`}
|
||||||
|
style={{ margin: 0 }}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
prefix={<TruckOutlined style={{ color: '#8c8c8c' }} />}
|
||||||
|
placeholder={`请输入 ${product.名称} 的物流单号`}
|
||||||
|
value={logisticsNumbers[product._id] || ''}
|
||||||
|
onChange={e => handleLogisticsNumberChange(product._id, e.target.value)}
|
||||||
|
style={{
|
||||||
|
fontSize: '14px',
|
||||||
|
borderColor: logisticsNumbers[product._id] ? '#52c41a' : undefined
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
))}
|
))}
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
{/* 提示信息 */}
|
||||||
|
{productList.length === 0 && (
|
||||||
|
<Card style={{ textAlign: 'center', marginTop: '20px' }}>
|
||||||
|
<Text type="secondary">
|
||||||
|
当前销售记录暂无产品信息
|
||||||
|
</Text>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ShipModal;
|
export default React.memo(ShipModal);
|
||||||
|
|||||||
641
src/pages/test/test5.tsx
Normal file
641
src/pages/test/test5.tsx
Normal file
@@ -0,0 +1,641 @@
|
|||||||
|
/**
|
||||||
|
* AI聊天页面组件 - 专业UI/UX设计版
|
||||||
|
* 作者: 阿瑞
|
||||||
|
* 功能: 现代化AI对话界面,注重视觉美观与用户体验
|
||||||
|
* 版本: 2.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { useState, useRef, useEffect, useMemo } from 'react';
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Input,
|
||||||
|
Avatar,
|
||||||
|
Typography,
|
||||||
|
Space,
|
||||||
|
Spin,
|
||||||
|
message,
|
||||||
|
Tooltip,
|
||||||
|
Dropdown,
|
||||||
|
Badge
|
||||||
|
} from 'antd';
|
||||||
|
import {
|
||||||
|
SendOutlined,
|
||||||
|
RobotOutlined,
|
||||||
|
UserOutlined,
|
||||||
|
ClearOutlined,
|
||||||
|
CopyOutlined,
|
||||||
|
LikeOutlined,
|
||||||
|
DislikeOutlined,
|
||||||
|
MoreOutlined,
|
||||||
|
ThunderboltOutlined,
|
||||||
|
StarOutlined,
|
||||||
|
SettingOutlined,
|
||||||
|
DownloadOutlined
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
|
||||||
|
const { TextArea } = Input;
|
||||||
|
const { Text, Title } = Typography;
|
||||||
|
|
||||||
|
// ============= 自定义样式 =============
|
||||||
|
|
||||||
|
const customStyles = `
|
||||||
|
.scrollbar-hide {
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.scrollbar-hide::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-slideUp {
|
||||||
|
animation: slideUp 0.4s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fadeIn {
|
||||||
|
animation: fadeIn 0.3s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-pulse-custom {
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 美化滚动条 */
|
||||||
|
.custom-scrollbar::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-track {
|
||||||
|
background: rgba(0, 0, 0, 0.05);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(139, 69, 19, 0.2);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: rgba(139, 69, 19, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 消息气泡悬浮效果 */
|
||||||
|
.message-bubble {
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-bubble:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮悬浮效果增强 */
|
||||||
|
.hover-lift {
|
||||||
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hover-lift:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 渐变文本 */
|
||||||
|
.gradient-text {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 毛玻璃效果增强 */
|
||||||
|
.glass-effect {
|
||||||
|
backdrop-filter: blur(20px) saturate(180%);
|
||||||
|
-webkit-backdrop-filter: blur(20px) saturate(180%);
|
||||||
|
background-color: rgba(255, 255, 255, 0.85);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.125);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入框聚焦效果 */
|
||||||
|
.ant-input:focus,
|
||||||
|
.ant-input-focused {
|
||||||
|
border-color: rgba(99, 102, 241, 0.6) !important;
|
||||||
|
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1) !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 注入样式到页面
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
const styleElement = document.createElement('style');
|
||||||
|
styleElement.textContent = customStyles;
|
||||||
|
if (!document.querySelector('[data-ai-chat-styles]')) {
|
||||||
|
styleElement.setAttribute('data-ai-chat-styles', 'true');
|
||||||
|
document.head.appendChild(styleElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= 类型定义区域 =============
|
||||||
|
|
||||||
|
interface ChatMessage {
|
||||||
|
id: string;
|
||||||
|
content: string;
|
||||||
|
sender: 'user' | 'ai';
|
||||||
|
timestamp: Date;
|
||||||
|
isLoading?: boolean;
|
||||||
|
liked?: boolean;
|
||||||
|
disliked?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChatPageProps {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= 主组件 =============
|
||||||
|
|
||||||
|
const AIChatPage: React.FC<ChatPageProps> = ({ className }) => {
|
||||||
|
// 聊天消息状态管理
|
||||||
|
const [messages, setMessages] = useState<ChatMessage[]>([
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
content: '👋 您好!我是您的AI智能助手。\n\n我可以帮助您解答问题、提供建议、协助创作等。请随时告诉我您需要什么帮助!',
|
||||||
|
sender: 'ai',
|
||||||
|
timestamp: new Date(),
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 输入和UI状态管理
|
||||||
|
const [inputValue, setInputValue] = useState<string>('');
|
||||||
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
|
const [isTyping, setIsTyping] = useState<boolean>(false);
|
||||||
|
|
||||||
|
// DOM引用
|
||||||
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||||
|
const inputRef = useRef<any>(null);
|
||||||
|
const chatContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// ============= 核心功能函数 =============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优雅的滚动到底部动画
|
||||||
|
*/
|
||||||
|
const scrollToBottom = () => {
|
||||||
|
messagesEndRef.current?.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'end'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const timer = setTimeout(scrollToBottom, 100);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [messages]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送消息处理 - 增强交互体验
|
||||||
|
*/
|
||||||
|
const handleSendMessage = async () => {
|
||||||
|
if (!inputValue.trim()) {
|
||||||
|
message.warning('💡 请输入您的问题');
|
||||||
|
inputRef.current?.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userMessage: ChatMessage = {
|
||||||
|
id: Date.now().toString(),
|
||||||
|
content: inputValue.trim(),
|
||||||
|
sender: 'user',
|
||||||
|
timestamp: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
setMessages(prev => [...prev, userMessage]);
|
||||||
|
setInputValue('');
|
||||||
|
setIsLoading(true);
|
||||||
|
setIsTyping(true);
|
||||||
|
|
||||||
|
// 模拟真实AI响应体验
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsTyping(false);
|
||||||
|
const aiMessage: ChatMessage = {
|
||||||
|
id: (Date.now() + 1).toString(),
|
||||||
|
content: generateAIResponse(userMessage.content),
|
||||||
|
sender: 'ai',
|
||||||
|
timestamp: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
setMessages(prev => [...prev, aiMessage]);
|
||||||
|
setIsLoading(false);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}, 300);
|
||||||
|
}, Math.random() * 1000 + 1500);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息反馈处理
|
||||||
|
*/
|
||||||
|
const handleMessageFeedback = (messageId: string, type: 'like' | 'dislike') => {
|
||||||
|
setMessages(prev => prev.map(msg =>
|
||||||
|
msg.id === messageId
|
||||||
|
? {
|
||||||
|
...msg,
|
||||||
|
liked: type === 'like' ? !msg.liked : false,
|
||||||
|
disliked: type === 'dislike' ? !msg.disliked : false
|
||||||
|
}
|
||||||
|
: msg
|
||||||
|
));
|
||||||
|
|
||||||
|
message.success(type === 'like' ? '👍 感谢您的反馈!' : '👎 我们会继续改进');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空聊天记录
|
||||||
|
*/
|
||||||
|
const handleClearChat = () => {
|
||||||
|
setMessages([{
|
||||||
|
id: '1',
|
||||||
|
content: '🔄 聊天记录已清空\n\n我是您的AI智能助手,准备好为您提供帮助了!',
|
||||||
|
sender: 'ai',
|
||||||
|
timestamp: new Date(),
|
||||||
|
}]);
|
||||||
|
message.success('✨ 聊天记录已清空');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制消息内容
|
||||||
|
*/
|
||||||
|
const handleCopyMessage = async (content: string) => {
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(content);
|
||||||
|
message.success('📋 消息已复制到剪贴板');
|
||||||
|
} catch (error) {
|
||||||
|
message.error('复制失败,请手动选择复制');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============= 工具函数 =============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 智能AI回复生成
|
||||||
|
*/
|
||||||
|
const generateAIResponse = (userInput: string): string => {
|
||||||
|
const responses = [
|
||||||
|
`✨ 我理解您关于"${userInput}"的问题。\n\n让我为您详细分析:这确实是一个很有深度的话题。从多个维度来看,我们可以考虑以下几个方面...\n\n如果您需要更具体的信息,请告诉我您最关心的是哪个方面?`,
|
||||||
|
|
||||||
|
`🎯 关于"${userInput}"这个话题,我很乐意为您解答。\n\n基于我的理解,这个问题涉及到几个关键点:\n• 首先需要考虑...\n• 其次要注意...\n• 最后建议...\n\n您希望我深入探讨哪个方面呢?`,
|
||||||
|
|
||||||
|
`💡 您提出了一个很棒的问题!"${userInput}"确实值得深入讨论。\n\n我的建议是:\n\n1️⃣ 从基础概念开始理解\n2️⃣ 分析具体应用场景\n3️⃣ 考虑实际操作方法\n\n需要我详细展开其中任何一个部分吗?`,
|
||||||
|
|
||||||
|
`🚀 很高兴您询问"${userInput}"相关的内容!\n\n这个领域有很多有趣的发展。让我为您整理一些关键信息:\n\n▸ 核心要点:...\n▸ 实践建议:...\n▸ 注意事项:...\n\n如果您想了解更多细节,我随时可以为您深入解释!`
|
||||||
|
];
|
||||||
|
return responses[Math.floor(Math.random() * responses.length)];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ============= 计算属性 =============
|
||||||
|
|
||||||
|
const chatStats = useMemo(() => ({
|
||||||
|
totalMessages: messages.length,
|
||||||
|
userMessages: messages.filter(m => m.sender === 'user').length,
|
||||||
|
aiMessages: messages.filter(m => m.sender === 'ai').length,
|
||||||
|
}), [messages]);
|
||||||
|
|
||||||
|
// 更多操作菜单
|
||||||
|
const moreMenuItems = [
|
||||||
|
{
|
||||||
|
key: 'export',
|
||||||
|
label: '导出聊天记录',
|
||||||
|
icon: <DownloadOutlined />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'settings',
|
||||||
|
label: '聊天设置',
|
||||||
|
icon: <SettingOutlined />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'feedback',
|
||||||
|
label: '意见反馈',
|
||||||
|
icon: <StarOutlined />,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// ============= 渲染函数 =============
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 ${className}`}>
|
||||||
|
{/* 背景装饰 */}
|
||||||
|
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
||||||
|
<div className="absolute -top-40 -right-40 w-80 h-80 bg-gradient-to-br from-purple-400/20 to-pink-400/20 rounded-full blur-3xl"></div>
|
||||||
|
<div className="absolute -bottom-40 -left-40 w-80 h-80 bg-gradient-to-tr from-blue-400/20 to-cyan-400/20 rounded-full blur-3xl"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative z-10 max-w-5xl mx-auto h-screen flex flex-col p-6">
|
||||||
|
|
||||||
|
{/* 精美的顶部导航栏 */}
|
||||||
|
<div className="glass-effect rounded-3xl p-6 mb-6 shadow-xl shadow-black/5 hover-lift">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<div className="flex items-center space-x-4">
|
||||||
|
<div className="relative">
|
||||||
|
<Avatar
|
||||||
|
size={48}
|
||||||
|
icon={<RobotOutlined />}
|
||||||
|
className="bg-gradient-to-br from-violet-500 via-purple-500 to-blue-500 border-4 border-white shadow-lg animate-pulse-custom"
|
||||||
|
/>
|
||||||
|
<Badge
|
||||||
|
status="processing"
|
||||||
|
className="absolute -bottom-1 -right-1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Title level={3} className="mb-1 gradient-text">
|
||||||
|
AI智能助手
|
||||||
|
</Title>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||||||
|
<Text className="text-sm text-gray-500 font-medium">在线服务中</Text>
|
||||||
|
<ThunderboltOutlined className="text-yellow-500 text-xs" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Space size="middle">
|
||||||
|
<div className="px-4 py-2 bg-gradient-to-r from-blue-50 to-indigo-50 rounded-full border border-blue-100">
|
||||||
|
<Text className="text-sm font-medium text-blue-700">
|
||||||
|
{chatStats.totalMessages} 条对话
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tooltip title="清空聊天记录" placement="bottom">
|
||||||
|
<Button
|
||||||
|
icon={<ClearOutlined />}
|
||||||
|
type="text"
|
||||||
|
onClick={handleClearChat}
|
||||||
|
className="w-10 h-10 rounded-full hover:bg-red-50 hover:text-red-500 transition-all duration-300"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Dropdown menu={{ items: moreMenuItems }} placement="bottomRight">
|
||||||
|
<Button
|
||||||
|
icon={<MoreOutlined />}
|
||||||
|
type="text"
|
||||||
|
className="w-10 h-10 rounded-full hover:bg-gray-50 transition-all duration-300"
|
||||||
|
/>
|
||||||
|
</Dropdown>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 聊天消息区域 */}
|
||||||
|
<div className="flex-1 glass-effect rounded-3xl shadow-xl shadow-black/5 overflow-hidden">
|
||||||
|
<div
|
||||||
|
ref={chatContainerRef}
|
||||||
|
className="h-full flex flex-col"
|
||||||
|
>
|
||||||
|
<div className="flex-1 overflow-y-auto p-8 space-y-6 custom-scrollbar">
|
||||||
|
{messages.map((message) => (
|
||||||
|
<MessageBubble
|
||||||
|
key={message.id}
|
||||||
|
message={message}
|
||||||
|
onCopy={handleCopyMessage}
|
||||||
|
onFeedback={handleMessageFeedback}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* AI思考状态 */}
|
||||||
|
{isLoading && (
|
||||||
|
<div className="flex justify-start animate-fadeIn">
|
||||||
|
<div className="flex items-center space-x-3 bg-gradient-to-r from-gray-50 to-blue-50 rounded-3xl px-6 py-4 border border-gray-100/50 shadow-sm">
|
||||||
|
<Avatar
|
||||||
|
size={32}
|
||||||
|
icon={<RobotOutlined />}
|
||||||
|
className="bg-gradient-to-br from-violet-500 to-blue-500"
|
||||||
|
/>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Spin size="small" />
|
||||||
|
<Text className="text-sm text-gray-600 font-medium">
|
||||||
|
{isTyping ? 'AI正在思考...' : '准备回复中...'}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div ref={messagesEndRef} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 消息输入区域 */}
|
||||||
|
<div className="p-8 bg-gradient-to-r from-gray-50/50 to-blue-50/30 border-t border-white/20">
|
||||||
|
<div className="flex items-end space-x-4">
|
||||||
|
<div className="flex-1 relative">
|
||||||
|
<TextArea
|
||||||
|
ref={inputRef}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={(e) => setInputValue(e.target.value)}
|
||||||
|
placeholder="✨ 输入您的问题,开始精彩对话..."
|
||||||
|
autoSize={{ minRows: 1, maxRows: 6 }}
|
||||||
|
onPressEnter={(e) => {
|
||||||
|
if (!e.shiftKey) {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSendMessage();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="border-0 bg-white/80 backdrop-blur-sm rounded-2xl px-4 py-3 text-base shadow-sm hover:shadow-md focus:shadow-lg transition-all duration-300 resize-none"
|
||||||
|
style={{
|
||||||
|
boxShadow: '0 4px 20px rgba(0,0,0,0.04)',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="flex justify-between items-center mt-3 px-2">
|
||||||
|
<Text className="text-xs text-gray-400">
|
||||||
|
Enter发送 • Shift+Enter换行
|
||||||
|
</Text>
|
||||||
|
<Text className="text-xs text-gray-400">
|
||||||
|
{inputValue.length}/2000
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<SendOutlined />}
|
||||||
|
onClick={handleSendMessage}
|
||||||
|
loading={isLoading}
|
||||||
|
disabled={!inputValue.trim()}
|
||||||
|
size="large"
|
||||||
|
className="h-14 px-8 bg-gradient-to-r from-violet-500 via-purple-500 to-blue-500 border-0 rounded-2xl shadow-lg hover:shadow-xl transform hover:scale-105 transition-all duration-300 font-medium"
|
||||||
|
>
|
||||||
|
发送
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============= 子组件 =============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 精美的消息气泡组件
|
||||||
|
*/
|
||||||
|
interface MessageBubbleProps {
|
||||||
|
message: ChatMessage;
|
||||||
|
onCopy: (content: string) => void;
|
||||||
|
onFeedback: (messageId: string, type: 'like' | 'dislike') => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MessageBubble: React.FC<MessageBubbleProps> = React.memo(({ message, onCopy, onFeedback }) => {
|
||||||
|
const isUser = message.sender === 'user';
|
||||||
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`flex ${isUser ? 'justify-end' : 'justify-start'} animate-slideUp`}
|
||||||
|
onMouseEnter={() => setIsHovered(true)}
|
||||||
|
onMouseLeave={() => setIsHovered(false)}
|
||||||
|
>
|
||||||
|
<div className={`flex items-end space-x-3 max-w-[85%] ${isUser ? 'flex-row-reverse space-x-reverse' : ''}`}>
|
||||||
|
|
||||||
|
{/* 头像 */}
|
||||||
|
<Avatar
|
||||||
|
size={40}
|
||||||
|
icon={isUser ? <UserOutlined /> : <RobotOutlined />}
|
||||||
|
className={`flex-shrink-0 shadow-lg border-2 border-white ${
|
||||||
|
isUser
|
||||||
|
? "bg-gradient-to-br from-emerald-400 via-blue-500 to-purple-600"
|
||||||
|
: "bg-gradient-to-br from-violet-500 via-purple-500 to-blue-500"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 消息内容容器 */}
|
||||||
|
<div className="flex flex-col space-y-2">
|
||||||
|
|
||||||
|
{/* 主消息气泡 */}
|
||||||
|
<div
|
||||||
|
className={`message-bubble relative px-6 py-4 rounded-3xl backdrop-blur-sm border ${
|
||||||
|
isUser
|
||||||
|
? 'bg-gradient-to-br from-violet-500 via-purple-500 to-blue-500 text-white border-violet-200/30 rounded-br-lg shadow-lg shadow-violet-500/25'
|
||||||
|
: 'bg-white/90 text-gray-800 border-gray-100/50 rounded-bl-lg shadow-lg shadow-black/5 hover:shadow-xl'
|
||||||
|
} ${isHovered ? 'transform scale-[1.02]' : ''}`}
|
||||||
|
>
|
||||||
|
|
||||||
|
{/* 消息内容 */}
|
||||||
|
<div className={`text-base leading-relaxed ${isUser ? 'text-white' : 'text-gray-800'}`}>
|
||||||
|
{message.content.split('\n').map((line, index) => (
|
||||||
|
<div key={index} className={index > 0 ? 'mt-2' : ''}>
|
||||||
|
{line}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 消息尾巴装饰 */}
|
||||||
|
<div
|
||||||
|
className={`absolute w-4 h-4 ${
|
||||||
|
isUser
|
||||||
|
? 'bottom-0 right-0 bg-gradient-to-br from-violet-500 to-blue-500 -mr-2 mb-2 transform rotate-45'
|
||||||
|
: 'bottom-0 left-0 bg-white -ml-2 mb-2 transform rotate-45 border-l border-b border-gray-100/50'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 时间戳和操作按钮 */}
|
||||||
|
<div className={`flex items-center space-x-3 px-3 ${isUser ? 'flex-row-reverse' : ''} transition-opacity duration-300 ${isHovered ? 'opacity-100' : 'opacity-60'}`}>
|
||||||
|
|
||||||
|
<Text className="text-xs text-gray-400 font-medium">
|
||||||
|
{formatTime(message.timestamp)}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{!isUser && (
|
||||||
|
<Space size={1}>
|
||||||
|
<Tooltip title="复制消息">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<CopyOutlined />}
|
||||||
|
onClick={() => onCopy(message.content)}
|
||||||
|
className="w-7 h-7 rounded-full text-gray-400 hover:text-blue-500 hover:bg-blue-50 transition-all duration-200"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip title={message.liked ? "已点赞" : "有用"}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<LikeOutlined />}
|
||||||
|
onClick={() => onFeedback(message.id, 'like')}
|
||||||
|
className={`w-7 h-7 rounded-full transition-all duration-200 ${
|
||||||
|
message.liked
|
||||||
|
? 'text-green-500 bg-green-50'
|
||||||
|
: 'text-gray-400 hover:text-green-500 hover:bg-green-50'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<Tooltip title={message.disliked ? "已反馈" : "无用"}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<DislikeOutlined />}
|
||||||
|
onClick={() => onFeedback(message.id, 'dislike')}
|
||||||
|
className={`w-7 h-7 rounded-full transition-all duration-200 ${
|
||||||
|
message.disliked
|
||||||
|
? 'text-red-500 bg-red-50'
|
||||||
|
: 'text-gray-400 hover:text-red-500 hover:bg-red-50'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
MessageBubble.displayName = 'MessageBubble';
|
||||||
|
|
||||||
|
// ============= 工具函数 =============
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间显示的通用函数
|
||||||
|
*/
|
||||||
|
function formatTime(date: Date): string {
|
||||||
|
const now = new Date();
|
||||||
|
const diff = now.getTime() - date.getTime();
|
||||||
|
|
||||||
|
if (diff < 60000) return '刚刚';
|
||||||
|
if (diff < 3600000) return `${Math.floor(diff / 60000)}分钟前`;
|
||||||
|
if (diff < 86400000) return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
|
||||||
|
return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric' });
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AIChatPage;
|
||||||
@@ -46,7 +46,11 @@ const useUserStore = create<UserStore>((set, get) => ({
|
|||||||
set({ userInfo });
|
set({ userInfo });
|
||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
localStorage.setItem('userInfo', JSON.stringify(userInfo));
|
localStorage.setItem('userInfo', JSON.stringify(userInfo));
|
||||||
//console.log('setUserInfo用户信息:', userInfo);
|
console.log('setUserInfo更新用户信息:', {
|
||||||
|
姓名: userInfo.姓名,
|
||||||
|
电话: userInfo.电话,
|
||||||
|
bark密钥: userInfo.bark密钥 ? '已配置' : '未配置'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 设置访问令牌和刷新令牌
|
// 设置访问令牌和刷新令牌
|
||||||
@@ -78,8 +82,8 @@ const useUserStore = create<UserStore>((set, get) => ({
|
|||||||
throw new Error('用户未登录或用户ID缺失');
|
throw new Error('用户未登录或用户ID缺失');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用原生fetch替代axios
|
// 使用完整的个人信息API获取详细数据
|
||||||
const response = await fetch(`/api/user?userId=${userId}`, {
|
const response = await fetch(`/api/backstage/mine/info/${userId}`, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -91,11 +95,10 @@ const useUserStore = create<UserStore>((set, get) => ({
|
|||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json();
|
const updatedUserInfo = await response.json();
|
||||||
const updatedUserInfo = data.userInfo;
|
|
||||||
setUserInfo(updatedUserInfo); // 更新用户信息
|
setUserInfo(updatedUserInfo); // 更新用户信息
|
||||||
//打印更新成功提示
|
//打印更新成功提示
|
||||||
console.log('用户信息更新成功!');
|
console.log('用户信息更新成功!', updatedUserInfo);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取用户信息失败:', error);
|
console.error('获取用户信息失败:', error);
|
||||||
message.error('无法更新用户信息');
|
message.error('无法更新用户信息');
|
||||||
@@ -107,8 +110,8 @@ const useUserStore = create<UserStore>((set, get) => ({
|
|||||||
// 为用户的 homePath 提供一个钩子
|
// 为用户的 homePath 提供一个钩子
|
||||||
export const useUserHomePath = () => {
|
export const useUserHomePath = () => {
|
||||||
const userInfo = useUserStore((state: UserStore) => state.userInfo);
|
const userInfo = useUserStore((state: UserStore) => state.userInfo);
|
||||||
const homePath = userInfo && userInfo.角色 ? userInfo.角色.主页 : '/index';
|
const homePath = userInfo && userInfo.角色 && userInfo.角色.主页 ? userInfo.角色.主页 : '/index';
|
||||||
//console.log('homePath:', homePath);
|
console.log('主页路径:', homePath, '用户角色信息:', userInfo?.角色);
|
||||||
return homePath;
|
return homePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,4 +125,18 @@ export const useUserToken = () => {
|
|||||||
const refreshToken = useUserStore((state: UserStore) => state.refreshToken);
|
const refreshToken = useUserStore((state: UserStore) => state.refreshToken);
|
||||||
return { accessToken, refreshToken };
|
return { accessToken, refreshToken };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 导出一个完整的用户信息钩子,包含刷新功能
|
||||||
|
export const useFullUserInfo = () => {
|
||||||
|
const userInfo = useUserStore((state: UserStore) => state.userInfo);
|
||||||
|
const { fetchAndSetUserInfo } = useUserStore((state: UserStore) => state.actions);
|
||||||
|
|
||||||
|
return {
|
||||||
|
userInfo,
|
||||||
|
refreshUserInfo: fetchAndSetUserInfo,
|
||||||
|
hasCompleteInfo: !!(userInfo._id && userInfo.姓名 && userInfo.电话 && userInfo.邮箱),
|
||||||
|
hasRoleHomePage: !!(userInfo.角色 && userInfo.角色.主页)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export default useUserStore;
|
export default useUserStore;
|
||||||
|
|||||||
Reference in New Issue
Block a user