diff --git a/Yi.Ai.Vue3/src/components/LoginDialog/components/QrCodeLogin/index.vue b/Yi.Ai.Vue3/src/components/LoginDialog/components/QrCodeLogin/index.vue index 601387d1..0031b25b 100644 --- a/Yi.Ai.Vue3/src/components/LoginDialog/components/QrCodeLogin/index.vue +++ b/Yi.Ai.Vue3/src/components/LoginDialog/components/QrCodeLogin/index.vue @@ -7,6 +7,7 @@ import { getQrCode, getQrCodeResult, getUserInfo } from '@/api'; import { useUserStore } from '@/stores'; import { useSessionStore } from '@/stores/modules/session.ts'; import { WECHAT_QRCODE_TYPE } from '@/utils/user.ts'; +import { useGuideTour } from '@/hooks/useGuideTour'; const props = defineProps({ type: { @@ -29,6 +30,7 @@ const userStore = useUserStore(); const router = useRouter(); const sessionStore = useSessionStore(); const isQrCodeError = ref(false); +const { startFullTour } = useGuideTour(); // 二维码倒计时实例 const { start: qrStart, stop: qrStop } = useCountdown(shallowRef(600), { interval: 1000, @@ -126,6 +128,11 @@ async function handleLoginSuccess(token: string, refreshToken: string) { stopPolling(); userStore.setToken(token, refreshToken); const resUserInfo = await getUserInfo(); + + // 判断是否为新用户(注册时间小于1小时) + const creationTime = resUserInfo.data.user.creationTime; // 格式: "2024-11-01 12:01:34" + const isNewUser = checkIsNewUser(creationTime); + userStore.setUserInfo(resUserInfo.data); // 提示用户 ElMessage.success('登录成功'); @@ -133,6 +140,34 @@ async function handleLoginSuccess(token: string, refreshToken: string) { await router.replace('/'); await sessionStore.requestSessionList(1, true); userStore.closeLoginDialog(); + + // 如果是新用户,延迟500ms后自动触发新手引导 + if (isNewUser) { + setTimeout(() => { + startFullTour(); + }, 500); + } +} + +// 判断是否为新用户(注册时间距离当前时间小于1小时) +function checkIsNewUser(creationTimeStr: string): boolean { + try { + // 解析注册时间字符串 "2024-11-01 12:01:34" + const creationTime = new Date(creationTimeStr.replace(' ', 'T')); + const currentTime = new Date(); + + // 计算时间差(毫秒) + const timeDiff = currentTime.getTime() - creationTime.getTime(); + + // 1小时 = 60分钟 * 60秒 * 1000毫秒 = 3600000毫秒 + const oneHourInMs = 60 * 60 * 1000; + + return timeDiff < oneHourInMs; + } + catch (error) { + console.error('解析注册时间失败:', error); + return false; + } } // 处理注册授权 diff --git a/Yi.Ai.Vue3/src/hooks/useGuideTour.ts b/Yi.Ai.Vue3/src/hooks/useGuideTour.ts index 99bbdd77..24add702 100644 --- a/Yi.Ai.Vue3/src/hooks/useGuideTour.ts +++ b/Yi.Ai.Vue3/src/hooks/useGuideTour.ts @@ -1,6 +1,6 @@ import { driver } from 'driver.js'; -import 'driver.js/dist/driver.css'; import { useGuideTourStore } from '@/stores'; +import 'driver.js/dist/driver.css'; // 引导步骤接口 interface TourStep { @@ -47,7 +47,7 @@ export function useGuideTour() { element: '[data-tour="tutorial-btn"]', popover: { title: '新手教程', - description: '欢迎使用YiXinAI!点击这里可以随时重新查看新手引导教程,帮助您快速了解系统功能。', + description: '欢迎使用意心AI-YiXinAI!点击这里可以随时重新查看新手引导教程,帮助您快速了解系统功能。', side: 'bottom', align: 'center', }, @@ -56,7 +56,7 @@ export function useGuideTour() { element: '[data-tour="model-select"]', popover: { title: '模型选择', - description: '点击这里可以切换不同的AI模型,每个模型有不同的特点和能力。VIP用户可以使用所有高级模型。', + description: '点击这里可以切换不同的AI模型,每个模型有不同的特点和能力。VIP用户可以更多高级模型。', side: 'top', align: 'start', }, @@ -65,7 +65,7 @@ export function useGuideTour() { element: '[data-tour="chat-sender"]', popover: { title: '对话输入框', - description: '在这里输入您的问题或指令,按回车或点击发送按钮即可与AI对话。支持语音输入和文件上传。', + description: '在这里输入您的问题或指令,按回车或点击发送按钮即可与AI对话。支持语音输入', side: 'top', align: 'center', }, @@ -92,7 +92,7 @@ export function useGuideTour() { element: '[data-tour="buy-btn"]', popover: { title: '立即购买', - description: '点击这里可以购买Token套餐或升级VIP会员,享受更多专属服务和权益。', + description: '点击这里可以成为VIP会员和升级尊享服务,享受更多专属服务和权益。', side: 'bottom', align: 'center', }, @@ -123,7 +123,7 @@ export function useGuideTour() { element: '[data-tour="nav-user"]', popover: { title: '用户信息', - description: '查看和修改您的个人信息,包括头像、昵称等。', + description: '查看您的个人信息,包括头像、昵称等。', side: 'right', align: 'center', }, @@ -171,7 +171,7 @@ export function useGuideTour() { element: '[data-tour="nav-premiumService"]', popover: { title: '尊享服务', - description: '了解VIP会员专属特权和服务,我们将详细介绍这个页面的功能。', + description: '了解尊享服务包专属特权和服务,我们将详细介绍这个页面的功能。', side: 'right', align: 'center', }, @@ -250,7 +250,6 @@ export function useGuideTour() { }, ]; - // 开始 Header 引导 async function startHeaderTour() { if (!driverInstance.value) { diff --git a/Yi.Ai.Vue3/src/layouts/components/Header/components/AnnouncementBtn.vue b/Yi.Ai.Vue3/src/layouts/components/Header/components/AnnouncementBtn.vue index 68fc7ebb..d14ee6ef 100644 --- a/Yi.Ai.Vue3/src/layouts/components/Header/components/AnnouncementBtn.vue +++ b/Yi.Ai.Vue3/src/layouts/components/Header/components/AnnouncementBtn.vue @@ -32,7 +32,10 @@ function openAnnouncement() { class="announcement-btn" @click="openAnnouncement" > - + + 公告/活动 + + @@ -44,65 +47,52 @@ function openAnnouncement() { .announcement-btn-container { display: flex; align-items: center; - margin-right: 12px; .announcement-badge { :deep(.el-badge__content) { background-color: #f56c6c; border: none; - //font-size: 12px; - //height: 18px; - //line-height: 18px; - //padding: 0 6px; } } .announcement-btn { - width: 40px; - height: 40px; display: flex; align-items: center; - justify-content: center; - border-radius: 50%; - background: transparent; + gap: 6px; cursor: pointer; - transition: all 0.3s; - - .el-icon { - color: #606266; - transition: color 0.3s; - } + font-size: 1.2rem; + font-weight: bold; + color: #e6a23c; + transition: all 0.2s; &:hover { - background: rgba(0, 0, 0, 0.05); + color: #ebb563; + transform: translateY(-1px); + } - .el-icon { - color: #409eff; - } + // PC端显示文字,隐藏图标 + .pc-text { + display: inline; + margin: 0 12px; + + } + + .mobile-icon { + display: none; } } } -// 移动端适配 -@media screen and (max-width: 768px) { +// 移动端显示图标,隐藏文字 +@media (max-width: 768px) { .announcement-btn-container { - margin-right: 8px; - .announcement-btn { - width: 36px; - height: 36px; - - .el-icon { - font-size: 18px; + .pc-text { + display: none; } - } - .announcement-badge { - :deep(.el-badge__content) { - //font-size: 10px; - //height: 16px; - //line-height: 16px; - //padding: 0 4px; + .mobile-icon { + display: inline; } } } diff --git a/Yi.Ai.Vue3/src/layouts/components/Header/components/TutorialBtn.vue b/Yi.Ai.Vue3/src/layouts/components/Header/components/TutorialBtn.vue index f229e15e..524ae1cd 100644 --- a/Yi.Ai.Vue3/src/layouts/components/Header/components/TutorialBtn.vue +++ b/Yi.Ai.Vue3/src/layouts/components/Header/components/TutorialBtn.vue @@ -12,16 +12,17 @@ function handleStartTutorial() { @@ -29,45 +30,44 @@ function handleStartTutorial() { .tutorial-btn-container { display: flex; align-items: center; - margin-right: 12px; .tutorial-btn { - width: 40px; - height: 40px; display: flex; align-items: center; - justify-content: center; - border-radius: 50%; - background: transparent; + gap: 6px; cursor: pointer; - transition: all 0.3s; - - .el-icon { - color: #606266; - transition: color 0.3s; - } + font-size: 1.2rem; + font-weight: bold; + color: #409eff; + transition: all 0.2s; &:hover { - background: rgba(0, 0, 0, 0.05); + color: #66b1ff; + transform: translateY(-1px); + } - .el-icon { - color: #409eff; - } + // PC端显示文字,隐藏图标 + .pc-text { + display: inline; + margin: 0 12px; + } + + .mobile-icon { + display: none; } } } -// 移动端适配 -@media screen and (max-width: 768px) { +// 移动端显示图标,隐藏文字 +@media (max-width: 768px) { .tutorial-btn-container { - margin-right: 8px; - .tutorial-btn { - width: 36px; - height: 36px; + .pc-text { + display: none; + } - .el-icon { - font-size: 18px; + .mobile-icon { + display: inline; } } } diff --git a/Yi.Ai.Vue3/src/layouts/components/Header/index.vue b/Yi.Ai.Vue3/src/layouts/components/Header/index.vue index c5a44c06..239624b4 100644 --- a/Yi.Ai.Vue3/src/layouts/components/Header/index.vue +++ b/Yi.Ai.Vue3/src/layouts/components/Header/index.vue @@ -71,8 +71,8 @@ onKeyStroke(event => event.ctrlKey && event.key.toLowerCase() === 'k', handleCtr
- +