feat: 更新志愿列表

master
xjs 2025-04-29 16:19:38 +08:00
parent 7253b03d58
commit 52e849324f
18 changed files with 579 additions and 66 deletions

View File

@ -15,6 +15,7 @@
"@coze/api": "1.2.0", "@coze/api": "1.2.0",
"@coze/realtime-api": "^1.1.1", "@coze/realtime-api": "^1.1.1",
"@microsoft/signalr": "^8.0.7", "@microsoft/signalr": "^8.0.7",
"@radix-ui/react-dialog": "^1.1.11",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-slot": "^1.2.0",
"@radix-ui/react-toast": "^1.2.7", "@radix-ui/react-toast": "^1.2.7",
@ -33,7 +34,7 @@
"sortablejs": "^1.15.3", "sortablejs": "^1.15.3",
"tailwind-merge": "^2.5.2", "tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.1", "vaul": "^0.9.9",
"zustand": "^4.5.5" "zustand": "^4.5.5"
}, },
"devDependencies": { "devDependencies": {

View File

@ -17,6 +17,9 @@ importers:
'@microsoft/signalr': '@microsoft/signalr':
specifier: ^8.0.7 specifier: ^8.0.7
version: 8.0.7 version: 8.0.7
'@radix-ui/react-dialog':
specifier: ^1.1.11
version: 1.1.11(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-icons': '@radix-ui/react-icons':
specifier: ^1.3.0 specifier: ^1.3.0
version: 1.3.2(react@18.3.1) version: 1.3.2(react@18.3.1)
@ -72,7 +75,7 @@ importers:
specifier: ^1.0.7 specifier: ^1.0.7
version: 1.0.7(tailwindcss@3.4.17) version: 1.0.7(tailwindcss@3.4.17)
vaul: vaul:
specifier: ^0.9.1 specifier: ^0.9.9
version: 0.9.9(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 0.9.9(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
zustand: zustand:
specifier: ^4.5.5 specifier: ^4.5.5
@ -466,8 +469,8 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-dialog@1.1.7': '@radix-ui/react-dialog@1.1.11':
resolution: {integrity: sha512-EIdma8C0C/I6kL6sO02avaCRqi3fmWJpxH6mqbVScorW6nNktzKJT/le7VPho3o/7wCsyRg3z0+Q+Obr0Gy/VQ==} resolution: {integrity: sha512-yI7S1ipkP5/+99qhSI6nthfo/tR6bL6Zgxi/+1UO6qPa6UeM6nlafWcQ65vB4rU2XjgjMfMhI3k9Y5MztA62VQ==}
peerDependencies: peerDependencies:
'@types/react': '*' '@types/react': '*'
'@types/react-dom': '*' '@types/react-dom': '*'
@ -505,6 +508,19 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-dismissable-layer@1.1.7':
resolution: {integrity: sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-focus-guards@1.0.1': '@radix-ui/react-focus-guards@1.0.1':
resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
peerDependencies: peerDependencies:
@ -536,8 +552,8 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-focus-scope@1.1.3': '@radix-ui/react-focus-scope@1.1.4':
resolution: {integrity: sha512-4XaDlq0bPt7oJwR+0k0clCiCO/7lO7NKZTAaJBYxDNQT/vj4ig0/UvctrRscZaFREpRvUTkpKR96ov1e6jptQg==} resolution: {integrity: sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA==}
peerDependencies: peerDependencies:
'@types/react': '*' '@types/react': '*'
'@types/react-dom': '*' '@types/react-dom': '*'
@ -598,6 +614,19 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-portal@1.1.6':
resolution: {integrity: sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-presence@1.0.1': '@radix-ui/react-presence@1.0.1':
resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==}
peerDependencies: peerDependencies:
@ -624,6 +653,19 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-presence@1.1.4':
resolution: {integrity: sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-primitive@1.0.3': '@radix-ui/react-primitive@1.0.3':
resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==}
peerDependencies: peerDependencies:
@ -650,6 +692,19 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-primitive@2.1.0':
resolution: {integrity: sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-slot@1.0.2': '@radix-ui/react-slot@1.0.2':
resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
peerDependencies: peerDependencies:
@ -717,6 +772,24 @@ packages:
'@types/react': '@types/react':
optional: true optional: true
'@radix-ui/react-use-controllable-state@1.2.2':
resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-use-effect-event@0.0.2':
resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-use-escape-keydown@1.0.3': '@radix-ui/react-use-escape-keydown@1.0.3':
resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==}
peerDependencies: peerDependencies:
@ -2907,20 +2980,20 @@ snapshots:
'@types/react': 18.3.20 '@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20) '@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-dialog@1.1.7(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-dialog@1.1.11(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/primitive': 1.1.2 '@radix-ui/primitive': 1.1.2
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-context': 1.1.2(@types/react@18.3.20)(react@18.3.1) '@radix-ui/react-context': 1.1.2(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-dismissable-layer': 1.1.6(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dismissable-layer': 1.1.7(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.20)(react@18.3.1) '@radix-ui/react-focus-guards': 1.1.2(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-focus-scope': 1.1.3(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-focus-scope': 1.1.4(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-id': 1.1.1(@types/react@18.3.20)(react@18.3.1) '@radix-ui/react-id': 1.1.1(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-portal': 1.1.5(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-portal': 1.1.6(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-presence': 1.1.3(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-presence': 1.1.4(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-primitive': 2.0.3(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-slot': 1.2.0(@types/react@18.3.20)(react@18.3.1) '@radix-ui/react-slot': 1.2.0(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-use-controllable-state': 1.1.1(@types/react@18.3.20)(react@18.3.1) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.20)(react@18.3.1)
aria-hidden: 1.2.4 aria-hidden: 1.2.4
react: 18.3.1 react: 18.3.1
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
@ -2956,6 +3029,19 @@ snapshots:
'@types/react': 18.3.20 '@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20) '@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-dismissable-layer@1.1.7(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/primitive': 1.1.2
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.20)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.20)(react@18.3.1)': '@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.20)(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.27.0 '@babel/runtime': 7.27.0
@ -2981,10 +3067,10 @@ snapshots:
'@types/react': 18.3.20 '@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20) '@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-focus-scope@1.1.3(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-focus-scope@1.1.4(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-primitive': 2.0.3(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.20)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.20)(react@18.3.1)
react: 18.3.1 react: 18.3.1
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
@ -3031,6 +3117,16 @@ snapshots:
'@types/react': 18.3.20 '@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20) '@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-portal@1.1.6(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/react-primitive': 2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.20)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-presence@1.0.1(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-presence@1.0.1(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.27.0 '@babel/runtime': 7.27.0
@ -3052,6 +3148,16 @@ snapshots:
'@types/react': 18.3.20 '@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20) '@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-presence@1.1.4(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.20)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.27.0 '@babel/runtime': 7.27.0
@ -3071,6 +3177,15 @@ snapshots:
'@types/react': 18.3.20 '@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20) '@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-primitive@2.1.0(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/react-slot': 1.2.0(@types/react@18.3.20)(react@18.3.1)
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.20
'@types/react-dom': 18.3.6(@types/react@18.3.20)
'@radix-ui/react-slot@1.0.2(@types/react@18.3.20)(react@18.3.1)': '@radix-ui/react-slot@1.0.2(@types/react@18.3.20)(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.27.0 '@babel/runtime': 7.27.0
@ -3134,6 +3249,21 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 18.3.20 '@types/react': 18.3.20
'@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.20)(react@18.3.1)':
dependencies:
'@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.20)(react@18.3.1)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.20)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.20
'@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.20)(react@18.3.1)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.20)(react@18.3.1)
react: 18.3.1
optionalDependencies:
'@types/react': 18.3.20
'@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.20)(react@18.3.1)': '@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.20)(react@18.3.1)':
dependencies: dependencies:
'@babel/runtime': 7.27.0 '@babel/runtime': 7.27.0
@ -5122,7 +5252,7 @@ snapshots:
vaul@0.9.9(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): vaul@0.9.9(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
'@radix-ui/react-dialog': 1.1.7(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dialog': 1.1.11(@types/react-dom@18.3.6(@types/react@18.3.20))(@types/react@18.3.20)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react: 18.3.1 react: 18.3.1
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
transitivePeerDependencies: transitivePeerDependencies:

BIN
public/icons/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
public/icons/wish-list.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -58,3 +58,19 @@ export const fetchFile = async ({
} }
}; };
export const fetchWishList = async ({
params,
options,
}: {
params: { locationCode: string; };
options?: { signal?: AbortSignal; headers?: Record<string, string> };
}) => {
const response = await getRequest("https://api.v3.ycymedu.com/api/volunTb/v2/list", params, options);
if (response.code === 200) {
return { result: response.result };
} else {
return { result: [], message: response.message };
}
};

View File

@ -11,6 +11,7 @@ import { useAbortController } from "@/hooks/useAbortController";
// import { ReportContext } from "@/components/Provider/ReportResolveProvider"; // import { ReportContext } from "@/components/Provider/ReportResolveProvider";
import AntechamberFile from "@/components/AntechamberFile"; import AntechamberFile from "@/components/AntechamberFile";
import AntechamberReport from "@/components/AntechamberReport"; import AntechamberReport from "@/components/AntechamberReport";
import AntechamberWishList from "@/components/AntechamberWishList";
export default function Antechamber() { export default function Antechamber() {
@ -100,6 +101,7 @@ export default function Antechamber() {
<div className="flex flex-col items-center h-full"> <div className="flex flex-col items-center h-full">
<AntechamberHeader toRoom={toRoom} /> <AntechamberHeader toRoom={toRoom} />
<AntechamberScore toRoom={toRoom} /> <AntechamberScore toRoom={toRoom} />
<AntechamberWishList />
<AntechamberFile /> <AntechamberFile />
<AntechamberReport /> <AntechamberReport />
<InvokeButton disable={disable} onClick={() => toRoom({})} /> <InvokeButton disable={disable} onClick={() => toRoom({})} />

3
src/base.css Normal file
View File

@ -0,0 +1,3 @@
*{
line-height: 1;
}

View File

@ -4,7 +4,7 @@ import { useAbortController } from "@/hooks/useAbortController";
import { useContext, useEffect } from "react"; import { useContext, useEffect } from "react";
import { useSearchParams } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { ReportContext } from "../Provider/ReportResolveProvider"; import { ReportContext } from "../Provider/ReportResolveProvider";
import { RealtimeClientContext } from "../Provider/RealtimeClientProvider"; import { FileInfo, RealtimeClientContext } from "../Provider/RealtimeClientProvider";
@ -31,10 +31,10 @@ export default function AntechamberFile() {
title: result.message, title: result.message,
}); });
} }
let url = result.result as string; let resp = result.result as FileInfo;
handleConnect({ handleConnect({
fileUrl: url, fileInfo: {type: resp.type,url: resp.url,tableName: resp.tableName,provinceName: resp.provinceName,subjectClaim: resp.subjectClaim},
}); });
setHasHandledReport(true); setHasHandledReport(true);
}; };

View File

@ -94,6 +94,7 @@
.change{ .change{
color:#2380e2; color:#2380e2;
font-size: 13px;
} }
.tip { .tip {

View File

@ -28,6 +28,7 @@
color: #1580FF; color: #1580FF;
display: flex; display: flex;
align-items: center; align-items: center;
font-size: 13px;
} }
.imgIcon{ .imgIcon{

View File

@ -0,0 +1,174 @@
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer";
import { X } from "lucide-react";
import { useWishList } from "@/hooks/useWishList";
import { useContext } from "react";
import {
FileInfo,
RealtimeClientContext,
} from "../Provider/RealtimeClientProvider";
import { fetchFile } from "@/apis/user";
import { useAbortController } from "@/hooks/useAbortController";
import { useSearchParams } from "react-router-dom";
import { toast } from "@/hooks/use-toast";
export default function AntechamberWishList() {
const { wishList } = useWishList();
const { handleConnect } = useContext(RealtimeClientContext);
const { getSignal } = useAbortController();
const [searchParams] = useSearchParams();
const token = searchParams.get("token") || "";
const handleNavigate = async (item: any) => {
const result = await fetchFile({
params: { id: item.vId, location: item.personlocationCode },
options: {
signal: getSignal(),
headers: { Authorization: `Bearer ${token}` },
},
});
if (result.message) {
toast({
title: result.message,
});
}
let resp = result.result as FileInfo;
handleConnect({
fileInfo: {
type: resp.type,
url: resp.url,
tableName: resp.tableName,
provinceName: resp.provinceName,
subjectClaim: resp.subjectClaim,
},
});
};
return (
<div className="w-full p-[15px]">
<div className="px-[12px] pt-[14px] pb-[16px] rounded-[13px] bg-[#fff]">
<div className="flex items-center justify-between">
<div className="w-[96px] h-[16px] object-contain">
<img src="/icons/wish-list.png" alt="wish-list" />
</div>
<Drawer>
<DrawerTrigger className="">
<div className="flex items-center text-[13px] text-[#1580FF]">
<img
src="/icons/arrow.png"
alt="arrow"
className="w-[16px] h-[16px] object-contain ml-[2px]"
/>
</div>
</DrawerTrigger>
<DrawerContent>
<DrawerHeader className="p-0">
<DrawerTitle>
<div className="py-[13px] relative bg-white rounded-[12px]">
<span className="text-[16px] text-[#333] font-[500]">
</span>
<DrawerClose>
<X className="absolute right-[13px] top-[10px] text-[#000] text-[16px]" />
</DrawerClose>
</div>
</DrawerTitle>
<div className="grid gap-[12px] px-[15px] pb-[15px] bg-[#F4F6FA] pt-[16px]">
{wishList.map((item: any) => (
<div className="w-full bg-white" key={item.vId}>
<div className="py-[10px] pl-[16px] pr-[13px] rounded-[8px] flex items-center">
<div className="flex flex-col">
<div className="flex items-center mb-[8px]">
<span className="text-[15px] font-[600] text-[#303030] mr-[5px]">
{item.tableName}
</span>
<div className="text-[10px] px-[4px] py-[2px] rounded-[4px] text-[#636363] bg-[#fff]">
{item.type}
</div>
<div></div>
</div>
<div className="text-[#303030] text-[11px] flex items-center">
<span>
{item.locationName}·{item.score}
</span>
<span className="ml-[8px]">
{item.subjectClaim.split(",").join("/")}
</span>
</div>
</div>
<div className="ml-auto">
<div className="text-[11px] text-[636363] font-[600] mb-[8px]">
{item.createTime}
</div>
<div
className="flex items-center justify-end text-[13px] text-[#1580FF]"
onClick={() => handleNavigate(item)}
>
<img
src="/icons/rightBlue.png"
alt=""
className="ml-[2px]"
/>
</div>
</div>
</div>
</div>
))}
</div>
</DrawerHeader>
<DrawerDescription>
<></>
</DrawerDescription>
</DrawerContent>
</Drawer>
</div>
{wishList.length > 0 ? (
<div className="p-[7px] rounded-[8px] bg-[#F4F6FA] flex items-center mt-[12px]">
<img
src="/icons/wish-list-icon.png"
alt="icon"
className="w-[46px] h-[46px] object-contain mr-[8px]"
/>
<div className="flex flex-col">
<div className="flex items-center mb-[5px]">
<span className="text-[15px] font-[600] text-[#303030] mr-[5px]">
{wishList[0].tableName}
</span>
<div className="text-[10px] px-[4px] py-[2px] rounded-[4px] text-[#636363] bg-[#fff]">
{wishList[0].type}
</div>
</div>
<div className="text-[#303030] text-[11px] flex items-center">
<span>
{wishList[0].locationName}·{wishList[0].score}
</span>
<span className="ml-[8px]">
{wishList[0].subjectClaim.split(",").join("/")}
</span>
</div>
</div>
<div
className="flex items-center text-[13px] text-[#1580FF] ml-auto"
onClick={() => handleNavigate(wishList[0])}
>
<img src="/icons/rightBlue.png" alt="" className="ml-[2px]" />
</div>
</div>
) : (
<></>
)}
</div>
</div>
);
}

View File

@ -23,6 +23,8 @@ type RoomInfo = {
uid: string; uid: string;
}; };
export type FileInfo = {type:string,url:string,tableName:string,provinceName:string,subjectClaim:string}
export const RealtimeClientContext = createContext<{ export const RealtimeClientContext = createContext<{
client: RealtimeClient | null; client: RealtimeClient | null;
isConnecting: boolean; isConnecting: boolean;
@ -32,20 +34,20 @@ export const RealtimeClientContext = createContext<{
messageList: { content: string; role: RoleType }[]; messageList: { content: string; role: RoleType }[];
isAiTalking: boolean; isAiTalking: boolean;
roomInfo: RoomInfo | null; roomInfo: RoomInfo | null;
fileParseStatus: number;
initClient: ({ initClient: ({
initMessage, initMessage,
fileUrl, fileInfo,
}: { }: {
initMessage?: string; initMessage?: string;
fileUrl?: string; fileInfo?: FileInfo;
}) => void; }) => void;
handleConnect: ({ handleConnect: ({
initMessage, initMessage,
fileUrl, fileInfo,
}: { }: {
initMessage?: string; initMessage?: string;
fileUrl?: string; fileInfo?: FileInfo;
}) => Promise<void>; }) => Promise<void>;
handleInterrupt: () => void; handleInterrupt: () => void;
handleDisconnect: () => void; handleDisconnect: () => void;
@ -59,7 +61,7 @@ export const RealtimeClientContext = createContext<{
messageList: [], messageList: [],
isAiTalking: false, isAiTalking: false,
roomInfo: null, roomInfo: null,
fileParseStatus: -1,
initClient: () => {}, initClient: () => {},
handleConnect: () => Promise.resolve(), handleConnect: () => Promise.resolve(),
handleInterrupt: () => {}, handleInterrupt: () => {},
@ -114,10 +116,10 @@ export const RealtimeClientProvider = ({
const initClient = async ({ const initClient = async ({
initMessage, initMessage,
fileUrl, fileInfo,
}: { }: {
initMessage?: string; initMessage?: string;
fileUrl?: string; fileInfo?: FileInfo;
}) => { }) => {
const permission = await RealtimeUtils.checkDevicePermission(false); const permission = await RealtimeUtils.checkDevicePermission(false);
const device = await RealtimeUtils.getAudioDevices(); const device = await RealtimeUtils.getAudioDevices();
@ -152,26 +154,28 @@ export const RealtimeClientProvider = ({
clientRef.current = client; clientRef.current = client;
setupEventListeners(client); setupEventListeners(client);
setupMessageEventListeners(client, { initMessage, fileUrl }); setupMessageEventListeners(client, { initMessage, fileInfo });
setupInitMessageEventListener(client, { initMessage, fileUrl }); setupInitMessageEventListener(client, { initMessage, fileInfo });
}; };
const handleConnect = async ({ const handleConnect = async ({
initMessage, initMessage,
fileUrl, fileInfo,
}: { }: {
initMessage?: string; initMessage?: string;
fileUrl?: string; fileInfo?: FileInfo;
}) => { }) => {
try { try {
if (!clientRef.current) { if (!clientRef.current) {
await initClient({ initMessage, fileUrl }); await initClient({ initMessage, fileInfo });
} else { } else {
await handleDisconnect(); await handleDisconnect();
await initClient({ initMessage, fileUrl }); await initClient({ initMessage, fileInfo });
} }
await clientRef.current?.connect(); await clientRef.current?.connect();
// await toggleMicrophone(); await clientRef.current?.setAudioEnable(false);
setAudioEnabled(false);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
if (error instanceof RealtimeAPIError) { if (error instanceof RealtimeAPIError) {
@ -207,8 +211,8 @@ export const RealtimeClientProvider = ({
// 关闭客户的时候清除一些信息 // 关闭客户的时候清除一些信息
setIsAiTalking(false); setIsAiTalking(false);
setMessageList([]); setMessageList([]);
// await clientRef.current?.setAudioEnable(false); await clientRef.current?.setAudioEnable(false);
// setAudioEnabled(false); setAudioEnabled(false);
await clientRef.current?.disconnect(); await clientRef.current?.disconnect();
clientRef.current?.clearEventHandlers(); clientRef.current?.clearEventHandlers();
@ -231,7 +235,7 @@ export const RealtimeClientProvider = ({
const setupInitMessageEventListener = useCallback( const setupInitMessageEventListener = useCallback(
( (
client: RealtimeClient, client: RealtimeClient,
{ initMessage, fileUrl }: { initMessage?: string; fileUrl?: string } { initMessage, fileInfo }: { initMessage?: string; fileInfo?: FileInfo }
) => { ) => {
client.on(EventNames.ALL_SERVER, async (eventName, _event: any) => { client.on(EventNames.ALL_SERVER, async (eventName, _event: any) => {
if (eventName === "server.session.created") { if (eventName === "server.session.created") {
@ -259,7 +263,7 @@ export const RealtimeClientProvider = ({
content: initMessage, content: initMessage,
}, },
}); });
} else if (eventName === "server.bot.join" && fileUrl) { } else if (eventName === "server.bot.join" && fileInfo) {
fileParseStatusRef.current = 0; fileParseStatusRef.current = 0;
await clientRef.current?.sendMessage({ await clientRef.current?.sendMessage({
@ -273,7 +277,7 @@ export const RealtimeClientProvider = ({
type: "text", type: "text",
text: "帮我解读这个文件,结合当下的专业行情以及对该专业未来的发展趋势,简介的给出大学建议", text: "帮我解读这个文件,结合当下的专业行情以及对该专业未来的发展趋势,简介的给出大学建议",
}, },
{ type: "image", file_url: fileUrl }, { type: "image", file_url: fileInfo.url },
]), ]),
}, },
}); });
@ -285,7 +289,7 @@ export const RealtimeClientProvider = ({
const setupMessageEventListeners = ( const setupMessageEventListeners = (
client: RealtimeClient, client: RealtimeClient,
{ initMessage, fileUrl }: { initMessage?: string; fileUrl?: string } { initMessage, fileInfo }: { initMessage?: string; fileInfo?: FileInfo }
) => { ) => {
client.on(EventNames.ALL, (_eventName, event: any) => { client.on(EventNames.ALL, (_eventName, event: any) => {
// AI智能体设置 // AI智能体设置
@ -301,6 +305,7 @@ export const RealtimeClientProvider = ({
const content = event.data.content; const content = event.data.content;
if ( if (
fileParseStatusRef.current === 0 &&
event.data.type === "function_call" && event.data.type === "function_call" &&
JSON.parse(content).name === "doc_reader-PDF_reader" JSON.parse(content).name === "doc_reader-PDF_reader"
) { ) {
@ -314,7 +319,6 @@ export const RealtimeClientProvider = ({
setMessageList((prev) => { setMessageList((prev) => {
// 如果上一个事件是增量更新,则附加到最后一条消息 // 如果上一个事件是增量更新,则附加到最后一条消息
if ( if (
prev.length > 0 && prev.length > 0 &&
prev[prev.length - 1].event?.event_type === prev[prev.length - 1].event?.event_type ===
@ -336,7 +340,7 @@ export const RealtimeClientProvider = ({
// 添加AI的欢迎语 // 添加AI的欢迎语
if ( if (
typeof initMessage === "undefined" && typeof initMessage === "undefined" &&
typeof fileUrl === "undefined" && typeof fileInfo === "undefined" &&
event.event_type === "conversation.created" event.event_type === "conversation.created"
) { ) {
return [ return [
@ -359,6 +363,8 @@ export const RealtimeClientProvider = ({
) { ) {
// lastEvent = event; // lastEvent = event;
if(event.event_type === ChatEventType.CONVERSATION_MESSAGE_DELTA && fileParseStatusRef.current === 2){ if(event.event_type === ChatEventType.CONVERSATION_MESSAGE_DELTA && fileParseStatusRef.current === 2){
console.log("重置了");
fileParseStatusRef.current = -1; fileParseStatusRef.current = -1;
} }
return [ return [
@ -379,6 +385,7 @@ export const RealtimeClientProvider = ({
role: RoleType.Assistant, role: RoleType.Assistant,
event: event, event: event,
fileParseStatus: fileParseStatusRef.current, fileParseStatus: fileParseStatusRef.current,
fileInfo: fileInfo,
}, },
]; ];
} else if ( } else if (
@ -392,6 +399,7 @@ export const RealtimeClientProvider = ({
role: prev[prev.length - 1].role, role: prev[prev.length - 1].role,
event: event, event: event,
fileParseStatus: fileParseStatusRef.current, fileParseStatus: fileParseStatusRef.current,
fileInfo: fileInfo,
}, },
]; ];
} else if ( } else if (
@ -405,6 +413,7 @@ export const RealtimeClientProvider = ({
role: RoleType.Assistant, role: RoleType.Assistant,
event: event, event: event,
fileParseStatus: fileParseStatusRef.current, fileParseStatus: fileParseStatusRef.current,
fileInfo: fileInfo,
}, },
]; ];
} }
@ -420,16 +429,16 @@ export const RealtimeClientProvider = ({
client.on(EventNames.AUDIO_AGENT_SPEECH_STARTED, async () => { client.on(EventNames.AUDIO_AGENT_SPEECH_STARTED, async () => {
// console.log("AI开始说话"); // console.log("AI开始说话");
setIsAiTalking(true); setIsAiTalking(true);
// await clientRef.current?.setAudioEnable(false); await clientRef.current?.setAudioEnable(false);
// setAudioEnabled(false); setAudioEnabled(false);
}); });
// 监听 AI 结束说话事件 // 监听 AI 结束说话事件
client.on(EventNames.AUDIO_AGENT_SPEECH_STOPPED, async () => { client.on(EventNames.AUDIO_AGENT_SPEECH_STOPPED, async () => {
// console.log("AI结束说话"); // console.log("AI结束说话");
setIsAiTalking(false); setIsAiTalking(false);
// await clientRef.current?.setAudioEnable(true); await clientRef.current?.setAudioEnable(true);
// setAudioEnabled(true); setAudioEnabled(true);
}); });
// 监听连接客户端 // 监听连接客户端
@ -444,6 +453,10 @@ export const RealtimeClientProvider = ({
setIsConnecting(false); setIsConnecting(false);
setIsConnected(true); setIsConnected(true);
}); });
client.on(EventNames.ERROR, (_error: any) => {
setIsConnected(false);
});
}, },
[clientRef.current] [clientRef.current]
); );
@ -459,7 +472,6 @@ export const RealtimeClientProvider = ({
messageList, messageList,
isAiTalking, isAiTalking,
roomInfo, roomInfo,
fileParseStatus: fileParseStatusRef.current,
initClient, initClient,
handleConnect, handleConnect,
handleInterrupt, handleInterrupt,

View File

@ -3,6 +3,7 @@ import { RealtimeClientContext } from "../Provider/RealtimeClientProvider";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
import gfm from "remark-gfm"; import gfm from "remark-gfm";
import { RoleType } from "@coze/api"; import { RoleType } from "@coze/api";
import { Loader } from 'lucide-react';
export default function RoomConversation() { export default function RoomConversation() {
const { messageList } = useContext(RealtimeClientContext); const { messageList } = useContext(RealtimeClientContext);
@ -24,19 +25,19 @@ export default function RoomConversation() {
<img <img
src="/icons/hello.gif" src="/icons/hello.gif"
alt="" alt=""
className="absolute top-0 h-[97px] left-[50%] translate-x-[-50%]" className="absolute top-0 h-[97px] left-[50%] translate-x-[-50%] object-contain"
/> />
<div className="text-black text-[14px] absolute bottom-[25px] left-[50%] translate-x-[-50%] z-[10] pt-[3px]">
<img <img
src="/icons/conversation-bg.png" src="/icons/conversation-bg.png"
alt="background" alt="background"
className="w-[222px] h-[49px] absolute bottom-0 left-[50%] translate-x-[-50%]" className="w-[252px] h-[49px] object-contain absolute top-[-50%] z-[-1] left-[50%] translate-x-[-50%]"
/> />
<div className="text-black text-[14px] absolute bottom-[22px] left-[50%] translate-x-[-50%] z-[10]">
HeyAI HeyAI
</div> </div>
</div> </div>
</div> </div>
<div className="flex-1 overflow-y-auto p-4 space-y-4"> <div className="p-4 space-y-4">
{messageList.map((message: any, index: number) => ( {messageList.map((message: any, index: number) => (
<div <div
key={index} key={index}
@ -53,9 +54,42 @@ export default function RoomConversation() {
: "bg-blue-500 text-white rounded-tr-none" : "bg-blue-500 text-white rounded-tr-none"
}`} }`}
> >
{typeof message.fileParseStatus === "undefined" ? (
<ReactMarkdown remarkPlugins={[gfm]}> <ReactMarkdown remarkPlugins={[gfm]}>
{message.content} {message.content}
</ReactMarkdown> </ReactMarkdown>
) : (
<div className="flex items-center justify-center px-[4px] py-[2px]">
<img
src="/icons/wish-list-icon.png"
alt="icon"
className="w-[48px] h-[48px] object-contain"
/>
<div className="flex flex-col items-start ml-[10px]">
<div className="flex items-center">
<span className="text-[15px] text-[#303030] mr-[8px] leading-[1]">
{message.fileInfo.tableName}
</span>
<div className="bg-[#F4F6FA] rounded-[4px] w-[48px] h-[16px] px-[4px] py-[2px] text-[10px]">
{message.fileInfo.type}
</div>
</div>
<div className="text-[12px] text-[#303030] mt-[6px] flex items-center">
<span className="mr-[10px]">
{message.fileInfo.provinceName}·{message.fileInfo.score}
</span>
<span>
{message.fileInfo.subjectClaim.split(",").join("/")}
</span>
{
message.fileParseStatus < 2 && (
<Loader className="w-[12px] h-[12px] animate-spin ml-[6px]" />
)
}
</div>
</div>
</div>
)}
</div> </div>
</div> </div>
))} ))}

View File

@ -0,0 +1,116 @@
import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul"
import { cn } from "@/lib/utils"
const Drawer = ({
shouldScaleBackground = true,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
{...props}
/>
)
Drawer.displayName = "Drawer"
const DrawerTrigger = DrawerPrimitive.Trigger
const DrawerPortal = DrawerPrimitive.Portal
const DrawerClose = DrawerPrimitive.Close
const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
))
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted hidden" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
))
DrawerContent.displayName = "DrawerContent"
const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
)
DrawerHeader.displayName = "DrawerHeader"
const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
)
DrawerFooter.displayName = "DrawerFooter"
const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName
const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DrawerDescription.displayName = DrawerPrimitive.Description.displayName
export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}

View File

@ -1,7 +0,0 @@
export const useTokenWithPat = () => {
// 替换成你的 PAT
const token = "pat_NhhZGW7sxkuyP4mJrPrVyZx20b3m6lymg0y2Ln9EyM0CV9q2f9t3rlGbtzppLQua"; // Access Token
return {
getToken: () => token
};
};

29
src/hooks/useWishList.ts Normal file
View File

@ -0,0 +1,29 @@
import { fetchWishList } from "@/apis/user";
import { useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";
import { useAbortController } from "./useAbortController";
export const useWishList = () => {
const [wishList, setWishList] = useState<any[]>([]);
const { getSignal } = useAbortController();
const [searchParams]= useSearchParams();
const locationCode = searchParams.get("locationCode") || '';
const token = searchParams.get("token") || '';
const getWishList = async () => {
const res = await fetchWishList({params:{locationCode:locationCode},options:{signal:getSignal(),headers: { Authorization: `Bearer ${token}` },}});
const _wishList = res.result as any[];
setWishList(_wishList);
};
useEffect(() => {
if(locationCode){
getWishList();
}
}, [locationCode]);
return {
wishList,
};
};

View File

@ -5,6 +5,7 @@ import { RouterProvider } from "react-router-dom";
import { router } from "@/router"; import { router } from "@/router";
import "./globals.css"; import "./globals.css";
import "./base.css";
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<StrictMode> <StrictMode>