test(component): ✅ 测试修改popover
This commit is contained in:
parent
d2275d5932
commit
d976d489a2
@ -13,6 +13,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
|
"@floating-ui/core": "^1.7.0",
|
||||||
|
"@floating-ui/dom": "^1.7.0",
|
||||||
|
"@floating-ui/vue": "^1.1.6",
|
||||||
"@jsonlee_12138/enum": "^1.0.4",
|
"@jsonlee_12138/enum": "^1.0.4",
|
||||||
"@vueuse/core": "^13.2.0",
|
"@vueuse/core": "^13.2.0",
|
||||||
"@vueuse/integrations": "^13.2.0",
|
"@vueuse/integrations": "^13.2.0",
|
||||||
|
|||||||
40
pnpm-lock.yaml
generated
40
pnpm-lock.yaml
generated
@ -11,6 +11,15 @@ importers:
|
|||||||
'@element-plus/icons-vue':
|
'@element-plus/icons-vue':
|
||||||
specifier: ^2.3.1
|
specifier: ^2.3.1
|
||||||
version: 2.3.1(vue@3.5.14(typescript@5.8.3))
|
version: 2.3.1(vue@3.5.14(typescript@5.8.3))
|
||||||
|
'@floating-ui/core':
|
||||||
|
specifier: ^1.7.0
|
||||||
|
version: 1.7.0
|
||||||
|
'@floating-ui/dom':
|
||||||
|
specifier: ^1.7.0
|
||||||
|
version: 1.7.0
|
||||||
|
'@floating-ui/vue':
|
||||||
|
specifier: ^1.1.6
|
||||||
|
version: 1.1.6(vue@3.5.14(typescript@5.8.3))
|
||||||
'@jsonlee_12138/enum':
|
'@jsonlee_12138/enum':
|
||||||
specifier: ^1.0.4
|
specifier: ^1.0.4
|
||||||
version: 1.0.4
|
version: 1.0.4
|
||||||
@ -599,6 +608,9 @@ packages:
|
|||||||
'@floating-ui/utils@0.2.9':
|
'@floating-ui/utils@0.2.9':
|
||||||
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
|
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
|
||||||
|
|
||||||
|
'@floating-ui/vue@1.1.6':
|
||||||
|
resolution: {integrity: sha512-XFlUzGHGv12zbgHNk5FN2mUB7ROul3oG2ENdTpWdE+qMFxyNxWSRmsoyhiEnpmabNm6WnUvR1OvJfUfN4ojC1A==}
|
||||||
|
|
||||||
'@humanfs/core@0.19.1':
|
'@humanfs/core@0.19.1':
|
||||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||||
engines: {node: '>=18.18.0'}
|
engines: {node: '>=18.18.0'}
|
||||||
@ -725,67 +737,56 @@ packages:
|
|||||||
resolution: {integrity: sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==}
|
resolution: {integrity: sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.41.0':
|
'@rollup/rollup-linux-arm-musleabihf@4.41.0':
|
||||||
resolution: {integrity: sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==}
|
resolution: {integrity: sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.41.0':
|
'@rollup/rollup-linux-arm64-gnu@4.41.0':
|
||||||
resolution: {integrity: sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==}
|
resolution: {integrity: sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.41.0':
|
'@rollup/rollup-linux-arm64-musl@4.41.0':
|
||||||
resolution: {integrity: sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==}
|
resolution: {integrity: sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-loongarch64-gnu@4.41.0':
|
'@rollup/rollup-linux-loongarch64-gnu@4.41.0':
|
||||||
resolution: {integrity: sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==}
|
resolution: {integrity: sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-powerpc64le-gnu@4.41.0':
|
'@rollup/rollup-linux-powerpc64le-gnu@4.41.0':
|
||||||
resolution: {integrity: sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==}
|
resolution: {integrity: sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.41.0':
|
'@rollup/rollup-linux-riscv64-gnu@4.41.0':
|
||||||
resolution: {integrity: sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==}
|
resolution: {integrity: sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-musl@4.41.0':
|
'@rollup/rollup-linux-riscv64-musl@4.41.0':
|
||||||
resolution: {integrity: sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==}
|
resolution: {integrity: sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.41.0':
|
'@rollup/rollup-linux-s390x-gnu@4.41.0':
|
||||||
resolution: {integrity: sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==}
|
resolution: {integrity: sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.41.0':
|
'@rollup/rollup-linux-x64-gnu@4.41.0':
|
||||||
resolution: {integrity: sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==}
|
resolution: {integrity: sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.41.0':
|
'@rollup/rollup-linux-x64-musl@4.41.0':
|
||||||
resolution: {integrity: sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==}
|
resolution: {integrity: sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-win32-arm64-msvc@4.41.0':
|
'@rollup/rollup-win32-arm64-msvc@4.41.0':
|
||||||
resolution: {integrity: sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==}
|
resolution: {integrity: sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==}
|
||||||
@ -1124,49 +1125,41 @@ packages:
|
|||||||
resolution: {integrity: sha512-jon9M7DKRLGZ9VYSkFMflvNqu9hDtOCEnO2QAryFWgT6o6AXU8du56V7YqnaLKr6rAbZBWYsYpikF226v423QA==}
|
resolution: {integrity: sha512-jon9M7DKRLGZ9VYSkFMflvNqu9hDtOCEnO2QAryFWgT6o6AXU8du56V7YqnaLKr6rAbZBWYsYpikF226v423QA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-arm64-musl@1.7.2':
|
'@unrs/resolver-binding-linux-arm64-musl@1.7.2':
|
||||||
resolution: {integrity: sha512-c8Cg4/h+kQ63pL43wBNaVMmOjXI/X62wQmru51qjfTvI7kmCy5uHTJvK/9LrF0G8Jdx8r34d019P1DVJmhXQpA==}
|
resolution: {integrity: sha512-c8Cg4/h+kQ63pL43wBNaVMmOjXI/X62wQmru51qjfTvI7kmCy5uHTJvK/9LrF0G8Jdx8r34d019P1DVJmhXQpA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-ppc64-gnu@1.7.2':
|
'@unrs/resolver-binding-linux-ppc64-gnu@1.7.2':
|
||||||
resolution: {integrity: sha512-A+lcwRFyrjeJmv3JJvhz5NbcCkLQL6Mk16kHTNm6/aGNc4FwPHPE4DR9DwuCvCnVHvF5IAd9U4VIs/VvVir5lg==}
|
resolution: {integrity: sha512-A+lcwRFyrjeJmv3JJvhz5NbcCkLQL6Mk16kHTNm6/aGNc4FwPHPE4DR9DwuCvCnVHvF5IAd9U4VIs/VvVir5lg==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-riscv64-gnu@1.7.2':
|
'@unrs/resolver-binding-linux-riscv64-gnu@1.7.2':
|
||||||
resolution: {integrity: sha512-hQQ4TJQrSQW8JlPm7tRpXN8OCNP9ez7PajJNjRD1ZTHQAy685OYqPrKjfaMw/8LiHCt8AZ74rfUVHP9vn0N69Q==}
|
resolution: {integrity: sha512-hQQ4TJQrSQW8JlPm7tRpXN8OCNP9ez7PajJNjRD1ZTHQAy685OYqPrKjfaMw/8LiHCt8AZ74rfUVHP9vn0N69Q==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-riscv64-musl@1.7.2':
|
'@unrs/resolver-binding-linux-riscv64-musl@1.7.2':
|
||||||
resolution: {integrity: sha512-NoAGbiqrxtY8kVooZ24i70CjLDlUFI7nDj3I9y54U94p+3kPxwd2L692YsdLa+cqQ0VoqMWoehDFp21PKRUoIQ==}
|
resolution: {integrity: sha512-NoAGbiqrxtY8kVooZ24i70CjLDlUFI7nDj3I9y54U94p+3kPxwd2L692YsdLa+cqQ0VoqMWoehDFp21PKRUoIQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-s390x-gnu@1.7.2':
|
'@unrs/resolver-binding-linux-s390x-gnu@1.7.2':
|
||||||
resolution: {integrity: sha512-KaZByo8xuQZbUhhreBTW+yUnOIHUsv04P8lKjQ5otiGoSJ17ISGYArc+4vKdLEpGaLbemGzr4ZeUbYQQsLWFjA==}
|
resolution: {integrity: sha512-KaZByo8xuQZbUhhreBTW+yUnOIHUsv04P8lKjQ5otiGoSJ17ISGYArc+4vKdLEpGaLbemGzr4ZeUbYQQsLWFjA==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-x64-gnu@1.7.2':
|
'@unrs/resolver-binding-linux-x64-gnu@1.7.2':
|
||||||
resolution: {integrity: sha512-dEidzJDubxxhUCBJ/SHSMJD/9q7JkyfBMT77Px1npl4xpg9t0POLvnWywSk66BgZS/b2Hy9Y1yFaoMTFJUe9yg==}
|
resolution: {integrity: sha512-dEidzJDubxxhUCBJ/SHSMJD/9q7JkyfBMT77Px1npl4xpg9t0POLvnWywSk66BgZS/b2Hy9Y1yFaoMTFJUe9yg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-linux-x64-musl@1.7.2':
|
'@unrs/resolver-binding-linux-x64-musl@1.7.2':
|
||||||
resolution: {integrity: sha512-RvP+Ux3wDjmnZDT4XWFfNBRVG0fMsc+yVzNFUqOflnDfZ9OYujv6nkh+GOr+watwrW4wdp6ASfG/e7bkDradsw==}
|
resolution: {integrity: sha512-RvP+Ux3wDjmnZDT4XWFfNBRVG0fMsc+yVzNFUqOflnDfZ9OYujv6nkh+GOr+watwrW4wdp6ASfG/e7bkDradsw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@unrs/resolver-binding-wasm32-wasi@1.7.2':
|
'@unrs/resolver-binding-wasm32-wasi@1.7.2':
|
||||||
resolution: {integrity: sha512-y797JBmO9IsvXVRCKDXOxjyAE4+CcZpla2GSoBQ33TVb3ILXuFnMrbR/QQZoauBYeOFuu4w3ifWLw52sdHGz6g==}
|
resolution: {integrity: sha512-y797JBmO9IsvXVRCKDXOxjyAE4+CcZpla2GSoBQ33TVb3ILXuFnMrbR/QQZoauBYeOFuu4w3ifWLw52sdHGz6g==}
|
||||||
@ -5266,6 +5259,15 @@ snapshots:
|
|||||||
|
|
||||||
'@floating-ui/utils@0.2.9': {}
|
'@floating-ui/utils@0.2.9': {}
|
||||||
|
|
||||||
|
'@floating-ui/vue@1.1.6(vue@3.5.14(typescript@5.8.3))':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/dom': 1.7.0
|
||||||
|
'@floating-ui/utils': 0.2.9
|
||||||
|
vue-demi: 0.14.10(vue@3.5.14(typescript@5.8.3))
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@vue/composition-api'
|
||||||
|
- vue
|
||||||
|
|
||||||
'@humanfs/core@0.19.1': {}
|
'@humanfs/core@0.19.1': {}
|
||||||
|
|
||||||
'@humanfs/node@0.16.6':
|
'@humanfs/node@0.16.6':
|
||||||
|
|||||||
34
src/components/DeepThinking/index.vue
Normal file
34
src/components/DeepThinking/index.vue
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<!-- 深度思考按钮 -->
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useChatStore } from '@/stores/modules/chat';
|
||||||
|
|
||||||
|
const chatStore = useChatStore();
|
||||||
|
|
||||||
|
const isDeepThinking = computed(() => chatStore.isDeepThinking);
|
||||||
|
|
||||||
|
// 切换是否深度思考
|
||||||
|
function setIsDeepThinking() {
|
||||||
|
chatStore.setDeepThinking(!chatStore.isDeepThinking);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
:class="{ 'is-select': isDeepThinking }"
|
||||||
|
class="deep-thinking-btn flex items-center p-10px rounded-10px rounded-15px cursor-pointer font-size-12px border-1px border-[rgba(0,0,0,0.08)] border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||||
|
@click="setIsDeepThinking"
|
||||||
|
>
|
||||||
|
<el-icon>
|
||||||
|
<ElementPlus />
|
||||||
|
</el-icon>
|
||||||
|
<span>深度思考</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.deep-thinking-btn.is-select {
|
||||||
|
color: var(--el-color-primary, #409eff);
|
||||||
|
border: 1px solid var(--el-color-primary, #409eff);
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -49,7 +49,7 @@ function handleClick(item: GetSessionListVO) {
|
|||||||
<Popover
|
<Popover
|
||||||
ref="popoverRef"
|
ref="popoverRef"
|
||||||
position="top-start"
|
position="top-start"
|
||||||
:offset="[-14, 14]"
|
:offset="[-14, 10]"
|
||||||
:trigger-style="{ cursor: 'pointer' }"
|
:trigger-style="{ cursor: 'pointer' }"
|
||||||
popover-class="popover-content"
|
popover-class="popover-content"
|
||||||
:popover-style="popoverStyle"
|
:popover-style="popoverStyle"
|
||||||
@ -58,7 +58,7 @@ function handleClick(item: GetSessionListVO) {
|
|||||||
<!-- 触发元素插槽 -->
|
<!-- 触发元素插槽 -->
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<div
|
<div
|
||||||
class="model-switch-box select-none flex items-center gap-4px px-10px py-8px rounded-15px cursor-pointer font-size-12px"
|
class="model-switch-box select-none flex items-center gap-4px p-10px rounded-10px cursor-pointer font-size-12px border-[rgba()]"
|
||||||
>
|
>
|
||||||
<div class="model-switch-box-icon">
|
<div class="model-switch-box-icon">
|
||||||
<SvgIcon name="models" size="12" />
|
<SvgIcon name="models" size="12" />
|
||||||
@ -70,7 +70,11 @@ function handleClick(item: GetSessionListVO) {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="popover-content-box">
|
<div class="popover-content-box">
|
||||||
<div v-for="item in popoverList" :key="item.id" class="popover-content-box-items h-full">
|
<div
|
||||||
|
v-for="item in popoverList"
|
||||||
|
:key="item.id"
|
||||||
|
class="popover-content-box-items flex rounded-8px select-none transition-all transition-duration-300 flex items-center gap-8px p-4px hover:cursor-pointer hover:bg-[rgba(0,0,0,.04)]"
|
||||||
|
>
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
popper-class="rounded-tooltip"
|
popper-class="rounded-tooltip"
|
||||||
effect="dark"
|
effect="dark"
|
||||||
@ -78,6 +82,7 @@ function handleClick(item: GetSessionListVO) {
|
|||||||
trigger="hover"
|
trigger="hover"
|
||||||
:offset="10"
|
:offset="10"
|
||||||
:show-arrow="false"
|
:show-arrow="false"
|
||||||
|
transition="zoom-fade"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="popover-content-box-item-text text-wrap max-w-200px rounded-lg">
|
<div class="popover-content-box-item-text text-wrap max-w-200px rounded-lg">
|
||||||
@ -85,16 +90,12 @@ function handleClick(item: GetSessionListVO) {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div
|
||||||
class="popover-content-box-item select-none transition-all transition-duration-300 flex items-center h-full gap-8px p-8px pl-10px pr-12px rounded-lg hover:cursor-pointer hover:bg-[rgba(0,0,0,.04)]"
|
class="popover-content-box-item font-size-12px text-overflow w-full line-height-16px"
|
||||||
:class="{ 'bg-[rgba(0,0,0,.04)] is-select': item.modelName === currentModelName }"
|
:class="{ 'bg-[rgba(0,0,0,.04)] is-select': item.modelName === currentModelName }"
|
||||||
@click="handleClick(item)"
|
@click="handleClick(item)"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="popover-content-box-item-text font-size-12px text-overflow max-h-120px line-height-snug"
|
|
||||||
>
|
>
|
||||||
{{ item.modelName }}
|
{{ item.modelName }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -106,11 +107,32 @@ function handleClick(item: GetSessionListVO) {
|
|||||||
.model-switch-box {
|
.model-switch-box {
|
||||||
color: var(--el-color-primary, #409eff);
|
color: var(--el-color-primary, #409eff);
|
||||||
border: 1px solid var(--el-color-primary, #409eff);
|
border: 1px solid var(--el-color-primary, #409eff);
|
||||||
border-radius: 15px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover-content-box-item.is-select {
|
.popover-content-box-item.is-select {
|
||||||
color: var(--el-color-primary, #409eff);
|
color: var(--el-color-primary, #409eff);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popover-content-box {
|
||||||
|
// background-color: red;
|
||||||
|
height: 200px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
|
||||||
|
// 滚动条样式
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
431
src/components/Popover/index copy.vue
Normal file
431
src/components/Popover/index copy.vue
Normal file
@ -0,0 +1,431 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { CSSProperties } from 'vue';
|
||||||
|
import { onClickOutside, useEventListener } from '@vueuse/core';
|
||||||
|
|
||||||
|
type PopoverPosition =
|
||||||
|
| 'top'
|
||||||
|
| 'top-start'
|
||||||
|
| 'top-end'
|
||||||
|
| 'bottom'
|
||||||
|
| 'bottom-start'
|
||||||
|
| 'bottom-end'
|
||||||
|
| 'left'
|
||||||
|
| 'left-start'
|
||||||
|
| 'left-end'
|
||||||
|
| 'right'
|
||||||
|
| 'right-start'
|
||||||
|
| 'right-end';
|
||||||
|
|
||||||
|
type Offset = [number, number];
|
||||||
|
const props = withDefaults(defineProps<PopoverProps>(), {
|
||||||
|
position: 'bottom',
|
||||||
|
offset: () => [8, 8],
|
||||||
|
boundary: 'viewport',
|
||||||
|
closeOnContentClick: false,
|
||||||
|
closeOnTriggerClick: false,
|
||||||
|
triggerStyle: () => ({}),
|
||||||
|
popoverStyle: () => ({}),
|
||||||
|
popoverClass: '',
|
||||||
|
});
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'show'): void;
|
||||||
|
(e: 'hide'): void;
|
||||||
|
(e: 'positionChange', pos: PopoverPosition): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const VIEWPORT_PADDING = 16;
|
||||||
|
interface PopoverProps {
|
||||||
|
position?: PopoverPosition;
|
||||||
|
offset?: Offset;
|
||||||
|
triggerStyle?: CSSProperties;
|
||||||
|
popoverStyle?: CSSProperties;
|
||||||
|
popoverClass?: string;
|
||||||
|
boundary?: 'viewport' | HTMLElement;
|
||||||
|
closeOnContentClick?: boolean;
|
||||||
|
closeOnTriggerClick?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const triggerRef = ref<HTMLElement | null>(null);
|
||||||
|
const popoverRef = ref<HTMLElement | null>(null);
|
||||||
|
const showPoperContent = ref(false);
|
||||||
|
const currentPosition = ref<PopoverPosition>(props.position);
|
||||||
|
let resizeObserver: ResizeObserver | null = null;
|
||||||
|
let mutationObserver: MutationObserver | null = null;
|
||||||
|
let updatePositionTimeout: number | null = null;
|
||||||
|
|
||||||
|
// 初始化尺寸与内容变化监听
|
||||||
|
function initObservers() {
|
||||||
|
if (!popoverRef.value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 监听弹出框尺寸变化
|
||||||
|
resizeObserver = new ResizeObserver(() => {
|
||||||
|
requestAnimationFrame(updatePosition);
|
||||||
|
});
|
||||||
|
resizeObserver.observe(popoverRef.value);
|
||||||
|
|
||||||
|
// 监听弹出框内容变化(子节点/样式变更)
|
||||||
|
mutationObserver = new MutationObserver((mutations) => {
|
||||||
|
for (const mutation of mutations) {
|
||||||
|
if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
|
||||||
|
updatePosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestAnimationFrame(updatePosition);
|
||||||
|
});
|
||||||
|
mutationObserver.observe(popoverRef.value, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
attributes: true,
|
||||||
|
attributeFilter: ['style', 'class'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 销毁监听
|
||||||
|
function destroyObservers() {
|
||||||
|
resizeObserver?.disconnect();
|
||||||
|
mutationObserver?.disconnect();
|
||||||
|
resizeObserver = null;
|
||||||
|
mutationObserver = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 强制更新定位(处理DOM缓存)
|
||||||
|
function updatePosition() {
|
||||||
|
if (!triggerRef.value || !popoverRef.value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 强制触发回流获取最新尺寸
|
||||||
|
triggerRef.value.getBoundingClientRect();
|
||||||
|
popoverRef.value.getBoundingClientRect();
|
||||||
|
|
||||||
|
const triggerRect = triggerRef.value.getBoundingClientRect();
|
||||||
|
const popoverRect = popoverRef.value.getBoundingClientRect();
|
||||||
|
const boundaryRect = getBoundaryRect();
|
||||||
|
|
||||||
|
const adjustedPos = adjustPosition(triggerRect, popoverRect, boundaryRect);
|
||||||
|
currentPosition.value = adjustedPos;
|
||||||
|
emits('positionChange', adjustedPos);
|
||||||
|
|
||||||
|
const { top, left, origin } = calculatePosition(triggerRect, popoverRect, adjustedPos);
|
||||||
|
popoverRef.value.style.top = `${top}px`;
|
||||||
|
popoverRef.value.style.left = `${left}px`;
|
||||||
|
popoverRef.value.style.transformOrigin = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 窗口尺寸变化防抖处理
|
||||||
|
useEventListener('resize', () => {
|
||||||
|
if (updatePositionTimeout)
|
||||||
|
clearTimeout(updatePositionTimeout);
|
||||||
|
updatePositionTimeout = setTimeout(updatePosition, 50);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示/隐藏状态监听
|
||||||
|
watch(
|
||||||
|
showPoperContent,
|
||||||
|
(newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
nextTick(() => {
|
||||||
|
initObservers();
|
||||||
|
updatePosition();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
destroyObservers();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
// 边界计算(保持不变)
|
||||||
|
function getBoundaryRect(): DOMRect {
|
||||||
|
if (props.boundary === 'viewport') {
|
||||||
|
return new DOMRect(0, 0, window.innerWidth, window.innerHeight);
|
||||||
|
}
|
||||||
|
return (props.boundary as HTMLElement).getBoundingClientRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定位计算(保持不变)
|
||||||
|
function calculatePosition(triggerRect: DOMRect, popoverRect: DOMRect, position: PopoverPosition) {
|
||||||
|
const [offsetX, offsetY] = props.offset!;
|
||||||
|
const { width: tW, height: tH } = triggerRect;
|
||||||
|
const { width: pW, height: pH } = popoverRect;
|
||||||
|
|
||||||
|
const positionMap: Record<PopoverPosition, { top: number; left: number; origin: string }> = {
|
||||||
|
'top': {
|
||||||
|
top: triggerRect.top - pH - offsetY,
|
||||||
|
left: triggerRect.left + tW / 2 - pW / 2 + offsetX,
|
||||||
|
origin: 'bottom center',
|
||||||
|
},
|
||||||
|
'top-start': {
|
||||||
|
top: triggerRect.top - pH - offsetY,
|
||||||
|
left: triggerRect.left + offsetX,
|
||||||
|
origin: 'bottom left',
|
||||||
|
},
|
||||||
|
'top-end': {
|
||||||
|
top: triggerRect.top - pH - offsetY,
|
||||||
|
left: triggerRect.left + tW - pW + offsetX,
|
||||||
|
origin: 'bottom right',
|
||||||
|
},
|
||||||
|
'bottom': {
|
||||||
|
top: triggerRect.bottom + offsetY,
|
||||||
|
left: triggerRect.left + tW / 2 - pW / 2 + offsetX,
|
||||||
|
origin: 'top center',
|
||||||
|
},
|
||||||
|
'bottom-start': {
|
||||||
|
top: triggerRect.bottom + offsetY,
|
||||||
|
left: triggerRect.left + offsetX,
|
||||||
|
origin: 'top left',
|
||||||
|
},
|
||||||
|
'bottom-end': {
|
||||||
|
top: triggerRect.bottom + offsetY,
|
||||||
|
left: triggerRect.left + tW - pW + offsetX,
|
||||||
|
origin: 'top right',
|
||||||
|
},
|
||||||
|
'left': {
|
||||||
|
top: triggerRect.top + tH / 2 - pH / 2 + offsetY,
|
||||||
|
left: triggerRect.left - pW - offsetX,
|
||||||
|
origin: 'right center',
|
||||||
|
},
|
||||||
|
'left-start': {
|
||||||
|
top: triggerRect.top + offsetY,
|
||||||
|
left: triggerRect.left - pW - offsetX,
|
||||||
|
origin: 'right top',
|
||||||
|
},
|
||||||
|
'left-end': {
|
||||||
|
top: triggerRect.top + tH - pH + offsetY,
|
||||||
|
left: triggerRect.left - pW - offsetX,
|
||||||
|
origin: 'right bottom',
|
||||||
|
},
|
||||||
|
'right': {
|
||||||
|
top: triggerRect.top + tH / 2 - pH / 2 + offsetY,
|
||||||
|
left: triggerRect.right + offsetX,
|
||||||
|
origin: 'left center',
|
||||||
|
},
|
||||||
|
'right-start': {
|
||||||
|
top: triggerRect.top + offsetY,
|
||||||
|
left: triggerRect.right + offsetX,
|
||||||
|
origin: 'left top',
|
||||||
|
},
|
||||||
|
'right-end': {
|
||||||
|
top: triggerRect.top + tH - pH + offsetY,
|
||||||
|
left: triggerRect.right + offsetX,
|
||||||
|
origin: 'left bottom',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return positionMap[position];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 边界调整(保持不变)
|
||||||
|
function adjustPosition(
|
||||||
|
triggerRect: DOMRect,
|
||||||
|
popoverRect: DOMRect,
|
||||||
|
boundaryRect: DOMRect,
|
||||||
|
): PopoverPosition {
|
||||||
|
const allPositions: PopoverPosition[] = [
|
||||||
|
'top',
|
||||||
|
'top-start',
|
||||||
|
'top-end',
|
||||||
|
'bottom',
|
||||||
|
'bottom-start',
|
||||||
|
'bottom-end',
|
||||||
|
'left',
|
||||||
|
'left-start',
|
||||||
|
'left-end',
|
||||||
|
'right',
|
||||||
|
'right-start',
|
||||||
|
'right-end',
|
||||||
|
];
|
||||||
|
const candidatePositions = [props.position, ...allPositions.filter(p => p !== props.position)];
|
||||||
|
|
||||||
|
for (const pos of candidatePositions) {
|
||||||
|
const { top, left } = calculatePosition(triggerRect, popoverRect, pos);
|
||||||
|
if (
|
||||||
|
top >= boundaryRect.top + VIEWPORT_PADDING
|
||||||
|
&& left >= boundaryRect.left + VIEWPORT_PADDING
|
||||||
|
&& top + popoverRect.height <= boundaryRect.bottom - VIEWPORT_PADDING
|
||||||
|
&& left + popoverRect.width <= boundaryRect.right - VIEWPORT_PADDING
|
||||||
|
) {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return props.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 交互逻辑(保持不变)
|
||||||
|
function handleTriggerClick() {
|
||||||
|
if (showPoperContent.value) {
|
||||||
|
props.closeOnTriggerClick && hidePopover();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
showPoperContent.value = true;
|
||||||
|
nextTick(() => emits('show'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleContentClick(e: MouseEvent) {
|
||||||
|
props.closeOnContentClick && hidePopover();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hidePopover() {
|
||||||
|
showPoperContent.value = false;
|
||||||
|
emits('hide');
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickOutside(popoverRef, () => !props.closeOnTriggerClick && hidePopover(), {
|
||||||
|
ignore: [triggerRef],
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
destroyObservers();
|
||||||
|
updatePositionTimeout && clearTimeout(updatePositionTimeout);
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({ show: () => (showPoperContent.value = true), hide: hidePopover });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
ref="triggerRef"
|
||||||
|
:style="props.triggerStyle"
|
||||||
|
role="button"
|
||||||
|
aria-haspopup="true"
|
||||||
|
:aria-expanded="showPoperContent"
|
||||||
|
@click.stop="handleTriggerClick"
|
||||||
|
>
|
||||||
|
<slot name="trigger" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Teleport to="body">
|
||||||
|
<Transition name="popover-fade" @before-enter="updatePosition">
|
||||||
|
<div
|
||||||
|
v-if="showPoperContent"
|
||||||
|
ref="popoverRef"
|
||||||
|
class="popover-content"
|
||||||
|
:style="props.popoverStyle"
|
||||||
|
:class="[props.popoverClass]"
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="false"
|
||||||
|
:data-popper-placement="currentPosition"
|
||||||
|
@click="handleContentClick"
|
||||||
|
>
|
||||||
|
<slot name="header" />
|
||||||
|
<slot />
|
||||||
|
<slot name="footer" />
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.popover-fade-enter-active,
|
||||||
|
.popover-fade-leave-active {
|
||||||
|
transition:
|
||||||
|
opacity 0.2s ease,
|
||||||
|
transform 0.2s ease;
|
||||||
|
will-change: transform, opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-fade-enter-from,
|
||||||
|
.popover-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-fade-enter-to,
|
||||||
|
.popover-fade-leave-from {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-content {
|
||||||
|
position: fixed;
|
||||||
|
min-width: 120px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 12px 16px;
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border: 6px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement^="top"]::before {
|
||||||
|
top: 100%;
|
||||||
|
border-top-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="top"]::before {
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="top-start"]::before {
|
||||||
|
left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="top-end"]::before {
|
||||||
|
right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement^="bottom"]::before {
|
||||||
|
bottom: 100%;
|
||||||
|
border-bottom-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="bottom"]::before {
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="bottom-start"]::before {
|
||||||
|
left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="bottom-end"]::before {
|
||||||
|
right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement^="left"]::before {
|
||||||
|
left: 100%;
|
||||||
|
border-left-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="left"]::before {
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="left-start"]::before {
|
||||||
|
top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="left-end"]::before {
|
||||||
|
bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement^="right"]::before {
|
||||||
|
right: 100%;
|
||||||
|
border-right-color: #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="right"]::before {
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="right-start"]::before {
|
||||||
|
top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-popper-placement="right-end"]::before {
|
||||||
|
bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,6 +1,29 @@
|
|||||||
|
<!-- Popover 弹框 -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { CSSProperties } from 'vue';
|
import type { CSSProperties } from 'vue';
|
||||||
import { onClickOutside } from '@vueuse/core';
|
import { flip, offset, shift, useFloating } from '@floating-ui/vue';
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<PopoverProps>(), {
|
||||||
|
position: 'bottom',
|
||||||
|
offset: () => [8, 8],
|
||||||
|
boundary: 'viewport',
|
||||||
|
closeOnContentClick: false,
|
||||||
|
closeOnTriggerClick: false,
|
||||||
|
triggerStyle: () => ({}),
|
||||||
|
popoverStyle: () => ({}),
|
||||||
|
popoverClass: '',
|
||||||
|
});
|
||||||
|
const emits = defineEmits<{
|
||||||
|
(e: 'show'): void;
|
||||||
|
(e: 'hide'): void;
|
||||||
|
(e: 'positionChange', pos: PopoverPosition): void;
|
||||||
|
}>();
|
||||||
|
const reference = ref();
|
||||||
|
const floating = ref(null);
|
||||||
|
const { floatingStyles } = useFloating(reference, floating, {
|
||||||
|
placement: props.position,
|
||||||
|
middleware: [offset(props.offset[0]), flip(), shift()],
|
||||||
|
});
|
||||||
|
|
||||||
type PopoverPosition =
|
type PopoverPosition =
|
||||||
| 'top'
|
| 'top'
|
||||||
@ -17,24 +40,6 @@ type PopoverPosition =
|
|||||||
| 'right-end';
|
| 'right-end';
|
||||||
|
|
||||||
type Offset = [number, number];
|
type Offset = [number, number];
|
||||||
const props = withDefaults(defineProps<PopoverProps>(), {
|
|
||||||
position: 'bottom',
|
|
||||||
offset: () => [8, 8],
|
|
||||||
boundary: 'viewport',
|
|
||||||
closeOnContentClick: false,
|
|
||||||
closeOnTriggerClick: false,
|
|
||||||
triggerStyle: () => ({}),
|
|
||||||
popoverStyle: () => ({}),
|
|
||||||
popoverClass: '',
|
|
||||||
});
|
|
||||||
const emits = defineEmits<{
|
|
||||||
(e: 'show'): void;
|
|
||||||
(e: 'hide'): void;
|
|
||||||
(e: 'positionChange', pos: PopoverPosition): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const VIEWPORT_PADDING = 16;
|
|
||||||
|
|
||||||
interface PopoverProps {
|
interface PopoverProps {
|
||||||
position?: PopoverPosition;
|
position?: PopoverPosition;
|
||||||
offset?: Offset;
|
offset?: Offset;
|
||||||
@ -46,362 +51,42 @@ interface PopoverProps {
|
|||||||
closeOnTriggerClick?: boolean;
|
closeOnTriggerClick?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const triggerRef = ref<HTMLElement | null>(null);
|
|
||||||
const popoverRef = ref<HTMLElement | null>(null);
|
|
||||||
const showPoperContent = ref(false);
|
const showPoperContent = ref(false);
|
||||||
const currentPosition = ref<PopoverPosition>(props.position);
|
|
||||||
|
|
||||||
// 新增:动画前钩子触发位置计算
|
|
||||||
function beforeEnter() {
|
|
||||||
updatePosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBoundaryRect() {
|
|
||||||
if (props.boundary === 'viewport') {
|
|
||||||
return {
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: window.innerWidth,
|
|
||||||
bottom: window.innerHeight,
|
|
||||||
width: window.innerWidth,
|
|
||||||
height: window.innerHeight,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
toJSON: () => ({}),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return (props.boundary as HTMLElement).getBoundingClientRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculatePosition(
|
|
||||||
triggerRect: DOMRect,
|
|
||||||
popoverRect: DOMRect,
|
|
||||||
position: PopoverPosition,
|
|
||||||
): { top: number; left: number; origin: string } {
|
|
||||||
const [offsetX, offsetY] = props.offset!; // 解构X/Y两个方向的偏移量
|
|
||||||
const { width: tWidth, height: tHeight } = triggerRect;
|
|
||||||
const { width: pWidth, height: pHeight } = popoverRect;
|
|
||||||
|
|
||||||
const positionMap: Record<PopoverPosition, { top: number; left: number; origin: string }> = {
|
|
||||||
// 上下方向位置(top/bottom系列):Y轴用offsetY,X轴用offsetX
|
|
||||||
'top': {
|
|
||||||
top: triggerRect.top - pHeight - offsetY, // Y轴:触发元素顶部到弹框底部的距离 - Y偏移
|
|
||||||
left: triggerRect.left + tWidth / 2 - pWidth / 2 + offsetX, // X轴:水平居中 + X偏移
|
|
||||||
origin: 'bottom center',
|
|
||||||
},
|
|
||||||
'top-start': {
|
|
||||||
top: triggerRect.top - pHeight - offsetY,
|
|
||||||
left: triggerRect.left + offsetX, // X轴:触发元素左侧 + X偏移
|
|
||||||
origin: 'bottom left',
|
|
||||||
},
|
|
||||||
'top-end': {
|
|
||||||
top: triggerRect.top - pHeight - offsetY,
|
|
||||||
left: triggerRect.left + tWidth - pWidth + offsetX, // X轴:触发元素右侧 - 弹框宽度 + X偏移
|
|
||||||
origin: 'bottom right',
|
|
||||||
},
|
|
||||||
'bottom': {
|
|
||||||
top: triggerRect.bottom + offsetY, // Y轴:触发元素底部 + Y偏移
|
|
||||||
left: triggerRect.left + tWidth / 2 - pWidth / 2 + offsetX, // X轴:水平居中 + X偏移
|
|
||||||
origin: 'top center',
|
|
||||||
},
|
|
||||||
'bottom-start': {
|
|
||||||
top: triggerRect.bottom + offsetY,
|
|
||||||
left: triggerRect.left + offsetX, // X轴:触发元素左侧 + X偏移
|
|
||||||
origin: 'top left',
|
|
||||||
},
|
|
||||||
'bottom-end': {
|
|
||||||
top: triggerRect.bottom + offsetY,
|
|
||||||
left: triggerRect.left + tWidth - pWidth + offsetX, // X轴:触发元素右侧 - 弹框宽度 + X偏移
|
|
||||||
origin: 'top right',
|
|
||||||
},
|
|
||||||
|
|
||||||
// 左右方向位置(left/right系列):X轴用offsetX,Y轴用offsetY
|
|
||||||
'left': {
|
|
||||||
top: triggerRect.top + tHeight / 2 - pHeight / 2 + offsetY, // Y轴:垂直居中 + Y偏移
|
|
||||||
left: triggerRect.left - pWidth - offsetX, // X轴:触发元素左侧 - 弹框宽度 - X偏移
|
|
||||||
origin: 'right center',
|
|
||||||
},
|
|
||||||
'left-start': {
|
|
||||||
top: triggerRect.top + offsetY, // Y轴:触发元素顶部 + Y偏移
|
|
||||||
left: triggerRect.left - pWidth - offsetX,
|
|
||||||
origin: 'right top',
|
|
||||||
},
|
|
||||||
'left-end': {
|
|
||||||
top: triggerRect.top + tHeight - pHeight + offsetY, // Y轴:触发元素底部 - 弹框高度 + Y偏移
|
|
||||||
left: triggerRect.left - pWidth - offsetX,
|
|
||||||
origin: 'right bottom',
|
|
||||||
},
|
|
||||||
'right': {
|
|
||||||
top: triggerRect.top + tHeight / 2 - pHeight / 2 + offsetY, // Y轴:垂直居中 + Y偏移
|
|
||||||
left: triggerRect.right + offsetX, // X轴:触发元素右侧 + X偏移
|
|
||||||
origin: 'left center',
|
|
||||||
},
|
|
||||||
'right-start': {
|
|
||||||
top: triggerRect.top + offsetY, // Y轴:触发元素顶部 + Y偏移
|
|
||||||
left: triggerRect.right + offsetX,
|
|
||||||
origin: 'left top',
|
|
||||||
},
|
|
||||||
'right-end': {
|
|
||||||
top: triggerRect.top + tHeight - pHeight + offsetY, // Y轴:触发元素底部 - 弹框高度 + Y偏移
|
|
||||||
left: triggerRect.right + offsetX,
|
|
||||||
origin: 'left bottom',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return positionMap[position];
|
|
||||||
}
|
|
||||||
|
|
||||||
function adjustPosition(
|
|
||||||
triggerRect: DOMRect,
|
|
||||||
popoverRect: DOMRect,
|
|
||||||
boundaryRect: DOMRect,
|
|
||||||
): PopoverPosition {
|
|
||||||
const allPositions: PopoverPosition[] = [
|
|
||||||
'top',
|
|
||||||
'top-start',
|
|
||||||
'top-end',
|
|
||||||
'bottom',
|
|
||||||
'bottom-start',
|
|
||||||
'bottom-end',
|
|
||||||
'left',
|
|
||||||
'left-start',
|
|
||||||
'left-end',
|
|
||||||
'right',
|
|
||||||
'right-start',
|
|
||||||
'right-end',
|
|
||||||
];
|
|
||||||
|
|
||||||
const candidatePositions = [props.position, ...allPositions.filter(p => p !== props.position)];
|
|
||||||
|
|
||||||
for (const pos of candidatePositions) {
|
|
||||||
const { top, left } = calculatePosition(triggerRect, popoverRect, pos);
|
|
||||||
if (
|
|
||||||
top >= boundaryRect.top + VIEWPORT_PADDING
|
|
||||||
&& left >= boundaryRect.left + VIEWPORT_PADDING
|
|
||||||
&& top + popoverRect.height <= boundaryRect.bottom - VIEWPORT_PADDING
|
|
||||||
&& left + popoverRect.width <= boundaryRect.right - VIEWPORT_PADDING
|
|
||||||
) {
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return props.position;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updatePosition() {
|
|
||||||
if (!triggerRef.value || !popoverRef.value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// 强制获取最新尺寸(避免缓存)
|
|
||||||
const triggerRect = triggerRef.value.getBoundingClientRect();
|
|
||||||
const popoverRect = popoverRef.value.getBoundingClientRect();
|
|
||||||
const boundaryRect = getBoundaryRect();
|
|
||||||
|
|
||||||
const adjustedPos = adjustPosition(triggerRect, popoverRect, boundaryRect);
|
|
||||||
currentPosition.value = adjustedPos;
|
|
||||||
emits('positionChange', adjustedPos);
|
|
||||||
|
|
||||||
const { top, left, origin } = calculatePosition(triggerRect, popoverRect, adjustedPos);
|
|
||||||
popoverRef.value.style.top = `${top}px`;
|
|
||||||
popoverRef.value.style.left = `${left}px`;
|
|
||||||
popoverRef.value.style.transformOrigin = origin;
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
[() => showPoperContent.value, () => props.position],
|
|
||||||
async ([newShow]) => {
|
|
||||||
if (newShow) {
|
|
||||||
// 等待弹框元素渲染完成
|
|
||||||
await nextTick();
|
|
||||||
updatePosition(); // 直接调用,无需 requestAnimationFrame
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
window.addEventListener('resize', updatePosition);
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
window.removeEventListener('resize', updatePosition);
|
|
||||||
});
|
|
||||||
|
|
||||||
function handleTriggerClick() {
|
function handleTriggerClick() {
|
||||||
|
showPoperContent.value = !showPoperContent.value;
|
||||||
if (showPoperContent.value) {
|
if (showPoperContent.value) {
|
||||||
if (props.closeOnTriggerClick)
|
emits('show');
|
||||||
hidePopover();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
showPoperContent.value = true;
|
emits('hide');
|
||||||
nextTick(() => emits('show'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleContentClick(e: MouseEvent) {
|
|
||||||
if (props.closeOnContentClick)
|
|
||||||
hidePopover();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
function hidePopover() {
|
|
||||||
showPoperContent.value = false;
|
|
||||||
emits('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickOutside(popoverRef, () => !props.closeOnTriggerClick && hidePopover(), {
|
|
||||||
ignore: [triggerRef],
|
|
||||||
});
|
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
show: () => (showPoperContent.value = true),
|
|
||||||
hide: hidePopover,
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div>
|
||||||
ref="triggerRef"
|
<div ref="reference" :style="props.triggerStyle" @click.stop="handleTriggerClick">
|
||||||
:style="props.triggerStyle"
|
|
||||||
role="button"
|
|
||||||
aria-haspopup="true"
|
|
||||||
:aria-expanded="showPoperContent"
|
|
||||||
@click.stop="handleTriggerClick"
|
|
||||||
>
|
|
||||||
<slot name="trigger" />
|
<slot name="trigger" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Teleport to="body">
|
<Transition name="popover-fade">
|
||||||
<Transition name="popover-fade" @before-enter="beforeEnter">
|
|
||||||
<div
|
<div
|
||||||
v-if="showPoperContent"
|
v-if="showPoperContent"
|
||||||
ref="popoverRef"
|
ref="floating"
|
||||||
class="popover-content"
|
class="popover-content"
|
||||||
:style="props.popoverStyle"
|
:style="{
|
||||||
|
...floatingStyles,
|
||||||
|
...props.popoverStyle,
|
||||||
|
}"
|
||||||
:class="[props.popoverClass]"
|
:class="[props.popoverClass]"
|
||||||
role="dialog"
|
|
||||||
aria-modal="false"
|
|
||||||
:data-popper-placement="currentPosition"
|
|
||||||
@click="handleContentClick"
|
|
||||||
>
|
>
|
||||||
<slot name="header" />
|
<slot name="header" />
|
||||||
<slot />
|
<slot />
|
||||||
<slot name="footer" />
|
<slot name="footer" />
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
</Teleport>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
/* 动画样式保持不变 */
|
|
||||||
.popover-fade-enter-active,
|
|
||||||
.popover-fade-leave-active {
|
|
||||||
transition:
|
|
||||||
opacity 0.2s ease,
|
|
||||||
transform 0.2s ease;
|
|
||||||
will-change: transform, opacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-fade-enter-from,
|
|
||||||
.popover-fade-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-fade-enter-to,
|
|
||||||
.popover-fade-leave-from {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-content {
|
|
||||||
position: fixed;
|
|
||||||
min-width: 120px;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #e5e7eb;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
||||||
padding: 12px 16px;
|
|
||||||
z-index: 1000;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
border: 6px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement^="top"]::before {
|
|
||||||
top: 100%;
|
|
||||||
border-top-color: #e5e7eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="top"]::before {
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="top-start"]::before {
|
|
||||||
left: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="top-end"]::before {
|
|
||||||
right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement^="bottom"]::before {
|
|
||||||
bottom: 100%;
|
|
||||||
border-bottom-color: #e5e7eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="bottom"]::before {
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="bottom-start"]::before {
|
|
||||||
left: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="bottom-end"]::before {
|
|
||||||
right: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement^="left"]::before {
|
|
||||||
left: 100%;
|
|
||||||
border-left-color: #e5e7eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="left"]::before {
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="left-start"]::before {
|
|
||||||
top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="left-end"]::before {
|
|
||||||
bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement^="right"]::before {
|
|
||||||
right: 100%;
|
|
||||||
border-right-color: #e5e7eb;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="right"]::before {
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="right-start"]::before {
|
|
||||||
top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-popper-placement="right-end"]::before {
|
|
||||||
bottom: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@ -95,7 +95,7 @@ function handleClick(item: any) {
|
|||||||
<Popover
|
<Popover
|
||||||
ref="popoverRef"
|
ref="popoverRef"
|
||||||
position="bottom-end"
|
position="bottom-end"
|
||||||
:offset="[-10, 8]"
|
:offset="[0, 8]"
|
||||||
:trigger-style="{ cursor: 'pointer' }"
|
:trigger-style="{ cursor: 'pointer' }"
|
||||||
popover-class="popover-content"
|
popover-class="popover-content"
|
||||||
:popover-style="popoverStyle"
|
:popover-style="popoverStyle"
|
||||||
|
|||||||
@ -66,24 +66,24 @@ provide('refresh', refreshMainPage);
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 带id聊天页面:中间缩放动画 */
|
/* 带id聊天页面:中间缩放动画 */
|
||||||
.zoom-fade-enter-from {
|
// .zoom-fade-enter-from {
|
||||||
transform: scale(0.8); /* 进入前:缩小隐藏 */
|
// transform: scale(0.9); /* 进入前:缩小隐藏 */
|
||||||
opacity: 0;
|
// opacity: 0;
|
||||||
}
|
// }
|
||||||
.zoom-fade-enter-active,
|
// .zoom-fade-enter-active,
|
||||||
.zoom-fade-leave-active {
|
// .zoom-fade-leave-active {
|
||||||
transition: all 0.3s; /* 缓入动画 */
|
// transition: all 0.3s; /* 缓入动画 */
|
||||||
}
|
// }
|
||||||
.zoom-fade-enter-to {
|
// .zoom-fade-enter-to {
|
||||||
transform: scale(1); /* 进入后:正常大小 */
|
// transform: scale(1); /* 进入后:正常大小 */
|
||||||
opacity: 1;
|
// opacity: 1;
|
||||||
}
|
// }
|
||||||
.zoom-fade-leave-from {
|
// .zoom-fade-leave-from {
|
||||||
transform: scale(1); /* 离开前:正常大小 */
|
// transform: scale(1); /* 离开前:正常大小 */
|
||||||
opacity: 1;
|
// opacity: 1;
|
||||||
}
|
// }
|
||||||
.zoom-fade-leave-to {
|
// .zoom-fade-leave-to {
|
||||||
transform: scale(0.8); /* 离开后:缩小隐藏 */
|
// transform: scale(0.9); /* 离开后:缩小隐藏 */
|
||||||
opacity: 0;
|
// opacity: 0;
|
||||||
}
|
// }
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -3,16 +3,12 @@
|
|||||||
import ModelSelect from '@/components/ModelSelect/index.vue';
|
import ModelSelect from '@/components/ModelSelect/index.vue';
|
||||||
import WelecomeText from '@/components/WelecomeText/index.vue';
|
import WelecomeText from '@/components/WelecomeText/index.vue';
|
||||||
import { useUserStore } from '@/stores';
|
import { useUserStore } from '@/stores';
|
||||||
import { useChatStore } from '@/stores/modules/chat';
|
|
||||||
import { useSessionStore } from '@/stores/modules/session';
|
import { useSessionStore } from '@/stores/modules/session';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const chatStore = useChatStore();
|
|
||||||
const sessionStore = useSessionStore();
|
const sessionStore = useSessionStore();
|
||||||
const senderValue = ref('');
|
const senderValue = ref('');
|
||||||
|
|
||||||
const isDeepThinking = computed(() => chatStore.isDeepThinking);
|
|
||||||
|
|
||||||
async function handleSend() {
|
async function handleSend() {
|
||||||
localStorage.setItem('chatContent', senderValue.value);
|
localStorage.setItem('chatContent', senderValue.value);
|
||||||
await sessionStore.createSessionList({
|
await sessionStore.createSessionList({
|
||||||
@ -22,11 +18,6 @@ async function handleSend() {
|
|||||||
remark: senderValue.value.slice(0, 10),
|
remark: senderValue.value.slice(0, 10),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置是否深度思考
|
|
||||||
function setIsDeepThinking() {
|
|
||||||
chatStore.setDeepThinking(!chatStore.isDeepThinking);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -47,25 +38,13 @@ function setIsDeepThinking() {
|
|||||||
<template #prefix>
|
<template #prefix>
|
||||||
<div class="flex-1 flex items-center gap-8px flex-none w-fit overflow-hidden">
|
<div class="flex-1 flex items-center gap-8px flex-none w-fit overflow-hidden">
|
||||||
<ModelSelect />
|
<ModelSelect />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex items-center gap-4px px-12px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
class="flex items-center gap-4px p-10px rounded-10px cursor-pointer font-size-14px border-1px border-[rgba(0,0,0,0.08)] border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||||
>
|
>
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<Paperclip />
|
<Paperclip />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
|
||||||
:class="{ 'is-select': isDeepThinking }"
|
|
||||||
class="flex items-center gap-4px px-10px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
|
||||||
@click="setIsDeepThinking"
|
|
||||||
>
|
|
||||||
<el-icon>
|
|
||||||
<ElementPlus />
|
|
||||||
</el-icon>
|
|
||||||
<span>深度思考</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Sender>
|
</Sender>
|
||||||
@ -85,11 +64,5 @@ function setIsDeepThinking() {
|
|||||||
.chat-defaul-sender {
|
.chat-defaul-sender {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-select {
|
|
||||||
color: var(--el-color-primary, #409eff);
|
|
||||||
border: 1px solid var(--el-color-primary, #409eff);
|
|
||||||
border-radius: 15px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -28,7 +28,6 @@ const { startStream: _, cancel, data, error, isLoading } = useXStream();
|
|||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const chatStore = useChatStore();
|
const chatStore = useChatStore();
|
||||||
const modelStore = useModelStore();
|
const modelStore = useModelStore();
|
||||||
const isDeepThinking = computed(() => chatStore.isDeepThinking);
|
|
||||||
const inputValue = ref('帮我写一篇小米手机介绍');
|
const inputValue = ref('帮我写一篇小米手机介绍');
|
||||||
const senderRef = ref<any>(null);
|
const senderRef = ref<any>(null);
|
||||||
const bubbleItems = ref<MessageItem[]>([]);
|
const bubbleItems = ref<MessageItem[]>([]);
|
||||||
@ -75,10 +74,6 @@ watch(
|
|||||||
{ immediate: true, deep: true },
|
{ immediate: true, deep: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
// 设置是否深度思考
|
|
||||||
function setIsDeepThinking() {
|
|
||||||
chatStore.setDeepThinking(!chatStore.isDeepThinking);
|
|
||||||
}
|
|
||||||
// 封装数据处理逻辑
|
// 封装数据处理逻辑
|
||||||
function handleDataChunk(chunk: string) {
|
function handleDataChunk(chunk: string) {
|
||||||
if (chunk === ' [DONE]') {
|
if (chunk === ' [DONE]') {
|
||||||
@ -253,23 +248,12 @@ function handleChange(payload: { value: boolean; status: ThinkingStatus }) {
|
|||||||
<template #prefix>
|
<template #prefix>
|
||||||
<div class="flex-1 flex items-center gap-8px flex-none w-fit overflow-hidden">
|
<div class="flex-1 flex items-center gap-8px flex-none w-fit overflow-hidden">
|
||||||
<div
|
<div
|
||||||
class="flex items-center gap-4px px-12px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
class="flex items-center gap-4px p-10px rounded-10px cursor-pointer font-size-14px border-1px border-[rgba(0,0,0,0.08)] border-solid hover:bg-[rgba(0,0,0,.04)]"
|
||||||
>
|
>
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<Paperclip />
|
<Paperclip />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
|
||||||
:class="{ 'is-select': isDeepThinking }"
|
|
||||||
class="flex items-center gap-4px px-10px py-8px rounded-15px cursor-pointer font-size-12px border-1px border-gray border-solid hover:bg-[rgba(0,0,0,.04)]"
|
|
||||||
@click="setIsDeepThinking"
|
|
||||||
>
|
|
||||||
<el-icon>
|
|
||||||
<ElementPlus />
|
|
||||||
</el-icon>
|
|
||||||
<span>深度思考</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -338,11 +322,5 @@ function handleChange(payload: { value: boolean; status: ThinkingStatus }) {
|
|||||||
margin-bottom: 22px;
|
margin-bottom: 22px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-select {
|
|
||||||
color: var(--el-color-primary, #409eff);
|
|
||||||
border: 1px solid var(--el-color-primary, #409eff);
|
|
||||||
border-radius: 15px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -20,10 +20,31 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rounded-tooltip
|
// rounded-tooltip 提示框样式
|
||||||
.rounded-tooltip {
|
.rounded-tooltip {
|
||||||
border-radius: 10px !important;
|
border-radius: 10px !important;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.zoom-fade-enter-from {
|
||||||
|
transform: scale(0.9); /* 进入前:缩小隐藏 */
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.zoom-fade-enter-active,
|
||||||
|
.zoom-fade-leave-active {
|
||||||
|
transition: transform 0.3s, opacity 0.3s; /* 缓入动画 */
|
||||||
|
}
|
||||||
|
.zoom-fade-enter-to {
|
||||||
|
transform: scale(1); /* 进入后:正常大小 */
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.zoom-fade-leave-from {
|
||||||
|
transform: scale(1); /* 离开前:正常大小 */
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.zoom-fade-leave-to {
|
||||||
|
transform: scale(0.9); /* 离开后:缩小隐藏 */
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|||||||
5
types/components.d.ts
vendored
5
types/components.d.ts
vendored
@ -3,12 +3,14 @@
|
|||||||
// Generated by unplugin-vue-components
|
// Generated by unplugin-vue-components
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
// biome-ignore lint: disable
|
// biome-ignore lint: disable
|
||||||
export {};
|
export {}
|
||||||
|
|
||||||
/* prettier-ignore */
|
/* prettier-ignore */
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
AccountPassword: typeof import('./../src/components/LoginDialog/components/FormLogin/AccountPassword.vue')['default']
|
AccountPassword: typeof import('./../src/components/LoginDialog/components/FormLogin/AccountPassword.vue')['default']
|
||||||
|
copy: typeof import('./../src/components/Popover/index copy.vue')['default']
|
||||||
|
DeepThinking: typeof import('./../src/components/DeepThinking/index.vue')['default']
|
||||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||||
ElButton: typeof import('element-plus/es')['ElButton']
|
ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||||
@ -23,6 +25,7 @@ declare module 'vue' {
|
|||||||
ElMain: typeof import('element-plus/es')['ElMain']
|
ElMain: typeof import('element-plus/es')['ElMain']
|
||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
IconSelect: typeof import('./../src/components/IconSelect/index.vue')['default']
|
IconSelect: typeof import('./../src/components/IconSelect/index.vue')['default']
|
||||||
|
'Index copy': typeof import('./../src/components/Popover/index copy.vue')['default']
|
||||||
LoginDialog: typeof import('./../src/components/LoginDialog/index.vue')['default']
|
LoginDialog: typeof import('./../src/components/LoginDialog/index.vue')['default']
|
||||||
ModelSelect: typeof import('./../src/components/ModelSelect/index.vue')['default']
|
ModelSelect: typeof import('./../src/components/ModelSelect/index.vue')['default']
|
||||||
Popover: typeof import('./../src/components/Popover/index.vue')['default']
|
Popover: typeof import('./../src/components/Popover/index.vue')['default']
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user