feat: 模型提示词、剩余额度、对话状态优化

This commit is contained in:
Gsh
2025-10-16 01:20:11 +08:00
parent c5c22224cf
commit 799dd08ec0
9 changed files with 158 additions and 70 deletions

View File

@@ -1,8 +1,10 @@
<!-- 切换模型 -->
<script setup lang="ts">
import type { GetSessionListVO } from '@/api/model/types';
import { Lock } from '@element-plus/icons-vue';
import { useRouter } from 'vue-router';
import Popover from '@/components/Popover/index.vue';
import SvgIcon from '@/components/SvgIcon/index.vue';
import { useUserStore } from '@/stores';
import { useModelStore } from '@/stores/modules/model';
@@ -10,6 +12,7 @@ import { showProductPackage } from '@/utils/product-package.ts';
import { isUserVip } from '@/utils/user';
const router = useRouter();
const userStore = useUserStore();
const modelStore = useModelStore();
// 检查模型是否可用
@@ -19,14 +22,21 @@ function isModelAvailable(item: GetSessionListVO) {
onMounted(async () => {
await modelStore.requestModelList();
if (modelStore.modelList.length > 0 && !modelStore.currentModelInfo?.modelId) {
// 设置默认模型
if (
modelStore.modelList.length > 0
&& (!modelStore.currentModelInfo || !modelStore.currentModelInfo.modelId)
) {
modelStore.setCurrentModelInfo(modelStore.modelList[0]);
}
});
const currentModelName = computed(() => modelStore.currentModelInfo?.modelName);
const currentModelName = computed(
() => modelStore.currentModelInfo && modelStore.currentModelInfo.modelName,
);
const popoverList = computed(() => modelStore.modelList);
/* 弹出面板 开始 */
const popoverStyle = ref({
width: '200px',
padding: '4px',
@@ -34,33 +44,38 @@ const popoverStyle = ref({
background: 'var(--el-bg-color, #fff)',
border: '1px solid var(--el-border-color-light)',
borderRadius: '8px',
boxShadow: '0 2px 12px rgba(0,0,0,0.1)',
boxShadow: '0 2px 12px 0 rgba(0, 0, 0, 0.1)',
});
const popoverRef = ref();
// 显示
async function showPopover() {
// 获取最新的模型列表
await modelStore.requestModelList();
}
/* -------------------------------
模型点击逻辑
-------------------------------- */
// 点击
// 处理模型点击
function handleModelClick(item: GetSessionListVO) {
if (!isModelAvailable(item)) {
ElMessageBox.confirm(
`
<div class="text-center leading-relaxed">
<h3 class="text-lg font-bold mb-3">${isUserVip() ? 'YiXinAI-VIP 会员' : '成为 YiXinAI-VIP'}</h3>
<p class="mb-2">
${isUserVip()
<div class="text-center leading-relaxed">
<h3 class="text-lg font-bold mb-3">${isUserVip() ? 'YiXinAI-VIP 会员' : '成为 YiXinAI-VIP'}</h3>
<p class="mb-2">
${
isUserVip()
? '您已是尊贵会员,享受全部 AI 模型与专属服务。感谢支持!'
: '解锁所有 AI 模型,无限加速,专属客服,尽享尊贵体验。'}
</p>
<p class="text-sm text-gray-500">
${isUserVip() ? '您可随时访问产品页面查看更多特权内容。' : '请点击右上角登录按钮,登录后进行购买!'}
</p>
</div>
`,
: '解锁所有 AI 模型,无限加速,专属客服,尽享尊贵体验。'
}
</p>
${
isUserVip()
? '<p class="text-sm text-gray-500">您可随时访问产品页面查看更多特权内容。</p>'
: '<p class="text-sm text-gray-500">请点击右上角登录按钮,登录后进行购买!</p>'
}
</div>
`,
isUserVip() ? '会员状态' : '会员尊享',
{
confirmButtonText: '产品查看',
@@ -70,7 +85,18 @@ function handleModelClick(item: GetSessionListVO) {
center: true,
roundButton: true,
},
).then(() => showProductPackage());
)
.then(() => {
showProductPackage();
// router.push({
// name: 'products', // 使用命名路由
// query: { from: isUserVip() ? 'vip' : 'user' }, // 可选:添加来源标识
// });
})
.catch(() => {
// 点击右上角关闭或“关闭”按钮,不执行任何操作
});
}
modelStore.setCurrentModelInfo(item);
@@ -83,8 +109,8 @@ function handleModelClick(item: GetSessionListVO) {
规则2金色光泽VIP/付费)
规则3彩色流光尊享/高级)
-------------------------------- */
function getModelStyleClass(item: GetSessionListVO) {
const name = item.modelName.toLowerCase();
function getModelStyleClass(modelName: any) {
const name = modelName.toLowerCase();
// 规则3彩色流光
if (name.includes('claude-sonnet-4-5-20250929')) {
@@ -123,7 +149,7 @@ function getWrapperClass(item: GetSessionListVO) {
? 'hover:scale-[1.03] hover:shadow-[0_0_8px_rgba(0,0,0,0.1)] hover:border-gray-300'
: 'opacity-60 cursor-not-allowed',
isSelected
? 'border-2 border-blue-700 shadow-[0_0_10px_rgba(29,78,216,0.6)]'
? 'border-2 border-blue-700 shadow-[0_0_10px_rgba(29,78,216,1)]'
: 'border border-transparent cursor-pointer',
];
}
@@ -135,33 +161,55 @@ function getWrapperClass(item: GetSessionListVO) {
ref="popoverRef"
placement="top-start"
:offset="[4, 0]"
popover-class="popover-content"
:popover-style="popoverStyle"
trigger="clickTarget"
@show="showPopover"
>
<!-- 触发元素插槽 -->
<template #trigger>
<div
class="flex items-center gap-1 p-2 rounded-md border border-blue-500 text-blue-600 cursor-pointer select-none model-select-box "
class="model-select-box select-none flex items-center gap-4px p-10px rounded-10px cursor-pointer font-size-12px border-[rgba()] leading-snug"
>
<SvgIcon name="models" size="12" />
<span class="text-sm font-medium">{{ currentModelName }}</span>
<div class="model-select-box-icon">
<SvgIcon name="models" size="12" />
</div>
<div :class="getModelStyleClass(currentModelName)" class="model-select-box-text font-size-12px">
{{ currentModelName }}
</div>
</div>
</template>
<div class="flex flex-col gap-1 max-h-100 overflow-y-auto p-1">
<div class="popover-content-box">
<div
v-for="item in popoverList"
:key="item.id"
:class="getWrapperClass(item)"
@click="handleModelClick(item)"
>
<span :class="getModelStyleClass(item)">
{{ item.modelName }}
</span>
<Popover
trigger-class="popover-trigger-item-text"
popover-class="rounded-tooltip"
placement="right"
trigger="hover"
:offset="[12, 0]"
>
<template #trigger>
<span :class="getModelStyleClass(item.modelName)">
{{ item.modelName }}
</span>
</template>
<div
class="popover-content-box-item-text text-wrap max-w-200px rounded-lg p-8px font-size-12px line-height-tight"
>
{{ item.remark }}
</div>
</Popover>
<!-- VIP锁定图标 -->
<el-icon
v-if="!isModelAvailable(item)"
class="absolute right-1 top-1/2 -translate-y-1/2 text-gray-400"
class="absolute right-1 top-1/2 transform -translate-y-1/2"
>
<Lock />
</el-icon>
@@ -171,7 +219,7 @@ function getWrapperClass(item: GetSessionListVO) {
</div>
</template>
<style scoped>
<style scoped lang="scss">
.model-select-box {
color: var(--el-color-primary, #409eff);
background: var(--el-color-primary-light-9, rgb(235.9 245.3 255));
@@ -179,6 +227,35 @@ function getWrapperClass(item: GetSessionListVO) {
border-radius: 10px;
}
.popover-content-box {
display: flex;
flex-direction: column;
gap: 4px;
height: 200px;
overflow: hidden auto;
:deep(.popover-trigger-item-text) {
width: 100%;
}
.popover-content-box-item-text {
color: white;
background-color: black;
}
// 滚动条样式
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-track {
background: #f5f5f5;
}
&::-webkit-scrollbar-thumb {
background: #cccccc;
border-radius: 4px;
}
}
/* 彩色流光动画 */
@keyframes gradientFlow {
0%, 100% { background-position: 0 50%; }