diff --git a/Yi.Ai.Vue3/.claude/settings.local.json b/Yi.Ai.Vue3/.claude/settings.local.json index 131db92e..13e6d318 100644 --- a/Yi.Ai.Vue3/.claude/settings.local.json +++ b/Yi.Ai.Vue3/.claude/settings.local.json @@ -2,7 +2,8 @@ "permissions": { "allow": [ "Bash(npx vue-tsc --noEmit)", - "Bash(timeout 60 npx vue-tsc:*)" + "Bash(timeout 60 npx vue-tsc:*)", + "Bash(npm run dev:*)" ], "deny": [], "ask": [] diff --git a/Yi.Ai.Vue3/src/components/userPersonalCenter/components/ActivationCode.vue b/Yi.Ai.Vue3/src/components/userPersonalCenter/components/ActivationCode.vue index 88541897..48c2766d 100644 --- a/Yi.Ai.Vue3/src/components/userPersonalCenter/components/ActivationCode.vue +++ b/Yi.Ai.Vue3/src/components/userPersonalCenter/components/ActivationCode.vue @@ -31,33 +31,33 @@ class Particle { this.x = x; this.y = y; this.hue = hue; - + // Explosive physics const angle = Math.random() * Math.PI * 2; - const speed = Math.random() * 15 + 2; + const speed = Math.random() * 15 + 2; this.vx = Math.cos(angle) * speed; this.vy = Math.sin(angle) * speed; - + this.alpha = 1; this.decay = Math.random() * 0.015 + 0.005; this.gravity = 0.05; - this.friction = 0.96; - + this.friction = 0.96; + this.size = Math.random() * 3 + 1; this.brightness = 50; // Standard brightness for white bg visibility (0-100% HSL L value) - this.flicker = Math.random() > 0.5; + this.flicker = Math.random() > 0.5; } update() { this.vx *= this.friction; this.vy *= this.friction; this.vy += this.gravity; - + this.x += this.vx; this.y += this.vy; - + this.alpha -= this.decay; - this.hue += 0.5; + this.hue += 0.5; } draw(ctx: CanvasRenderingContext2D) { @@ -65,9 +65,9 @@ class Particle { // On white background: // We want high saturation (100%) and medium lightness (50%) to make colors pop against white. // If lightness is too high (like 80-100), it fades into white. - const lightness = this.flicker ? Math.random() * 20 + 40 : this.brightness; + const lightness = this.flicker ? Math.random() * 20 + 40 : this.brightness; ctx.fillStyle = `hsla(${this.hue}, 100%, ${lightness}%, ${this.alpha})`; - + ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); @@ -93,7 +93,7 @@ class Shockwave { } update() { - this.radius += 15; + this.radius += 15; this.alpha -= 0.05; this.lineWidth -= 0.2; } @@ -132,10 +132,10 @@ function animate() { if (!ctx) return; // Clear with transparent fade for trails on white - // 'destination-out' erases content. + // 'destination-out' erases content. // To leave a trail on a white background (canvas is transparent over white gradient): // We need to gently erase what's there. - + ctx.globalCompositeOperation = 'destination-out'; ctx.fillStyle = 'rgba(255, 255, 255, 0.1)'; // Alpha controls trail length ctx.fillRect(0, 0, canvas.width, canvas.height); @@ -177,14 +177,14 @@ function triggerCelebration() { canvas.width = parent.clientWidth; canvas.height = parent.clientHeight; } - + const cx = canvas.width / 2; const cy = canvas.height / 2; // 1. Initial Mega Explosion triggerShake(); createExplosion(cx, cy, Math.random() * 360); - + // Start loop animate(); @@ -194,15 +194,15 @@ function triggerCelebration() { count++; const rx = cx + (Math.random() - 0.5) * canvas.width * 0.8; const ry = cy + (Math.random() - 0.5) * canvas.height * 0.8; - + createExplosion(rx, ry, Math.random() * 360); - - if (count % 3 === 0) triggerShake(); + + if (count % 3 === 0) triggerShake(); if (count > 25) { clearInterval(timer); } - }, 120); + }, 120); } async function handleRedeem() { @@ -221,7 +221,7 @@ async function handleRedeem() { duration: 3000, showClose: true, }); - activationCode.value = ''; + activationCode.value = ''; } catch (error: any) { // console.error(error); } finally { @@ -238,13 +238,13 @@ onUnmounted(() => {
- +
🎁
- +

激活码兑换

开启您的专属惊喜权益

@@ -258,9 +258,9 @@ onUnmounted(() => { clearable @keyup.enter="handleRedeem" /> - - @@ -321,7 +321,7 @@ onUnmounted(() => { .content-wrapper { position: relative; - z-index: 11; + z-index: 11; width: 100%; max-width: 480px; padding: 40px; diff --git a/Yi.Ai.Vue3/src/components/userPersonalCenter/components/UsageStatistics.vue b/Yi.Ai.Vue3/src/components/userPersonalCenter/components/UsageStatistics.vue index 8be7425f..e0baea70 100644 --- a/Yi.Ai.Vue3/src/components/userPersonalCenter/components/UsageStatistics.vue +++ b/Yi.Ai.Vue3/src/components/userPersonalCenter/components/UsageStatistics.vue @@ -549,6 +549,7 @@ onBeforeUnmount(() => { @@ -180,7 +187,9 @@ function bindWechat() { 昵称
-
{{ userNick }}
+
+ {{ userNick }} +
@@ -215,7 +224,9 @@ function bindWechat() {
- + + + 微信绑定
diff --git a/Yi.Ai.Vue3/src/config/design.ts b/Yi.Ai.Vue3/src/config/design.ts index 44995efd..6d597f54 100644 --- a/Yi.Ai.Vue3/src/config/design.ts +++ b/Yi.Ai.Vue3/src/config/design.ts @@ -1,4 +1,4 @@ -export type LayoutType = | 'vertical' | 'blankPage'; +export type LayoutType = 'default' | 'vertical' | 'blankPage' | 'blankPage'; // 仿豆包折叠逻辑 export type CollapseType @@ -25,7 +25,7 @@ export interface DesignConfigState { // 是否折叠菜单 isCollapse: boolean; // 安全区是否被悬停 - isSafeAreaHover: boolean; + isCollapseConversationList: boolean; // 跟踪是否首次激活悬停 hasActivatedHover: boolean; } @@ -65,15 +65,13 @@ const design: DesignConfigState = { // 需要自定义路由动画可以把 Main 组件样式代码注释放开,从新对话切换到带id的路由时,会执行这个动画样式 pageAnimateType: 'zoom-fade', // 布局模式 (纵向:vertical | ... | 自己定义) - layout: 'vertical', + layout: 'default', // 折叠类型 collapseType: 'followSystem', - // 是否折叠菜单 + // 是否折叠对话记录菜单 isCollapse: false, - // 安全区是否被悬停 - isSafeAreaHover: false, - // 跟踪是否首次激活悬停 - hasActivatedHover: false, + // 是否折叠对话记录菜单 + isCollapseConversationList: false, }; export default design; diff --git a/Yi.Ai.Vue3/src/hooks/useResponsive.ts b/Yi.Ai.Vue3/src/hooks/useResponsive.ts new file mode 100644 index 00000000..2c57ef32 --- /dev/null +++ b/Yi.Ai.Vue3/src/hooks/useResponsive.ts @@ -0,0 +1,72 @@ +import { useBreakpoints, useWindowSize } from '@vueuse/core'; +import { computed } from 'vue'; + +// 断点定义 +export const breakpoints = { + xs: 0, // 手机竖屏 < 640px + sm: 640, // 手机横屏 ≥ 640px + md: 768, // 平板 ≥ 768px + lg: 1024, // 小桌面 ≥ 1024px + xl: 1280, // 桌面 ≥ 1280px + xxl: 1536, // 大桌面 ≥ 1536px +}; + +export function useResponsive() { + const bp = useBreakpoints(breakpoints); + + // 设备类型判断 + const isMobile = bp.smaller('md'); // < 768px + const isTablet = bp.between('md', 'lg'); // 768px - 1024px + const isDesktop = bp.greaterOrEqual('lg'); // ≥ 1024px + + // 精确断点 + const isXs = bp.smaller('sm'); // < 640px + const isSm = bp.between('sm', 'md'); // 640px - 768px + const isMd = bp.between('md', 'lg'); // 768px - 1024px + const isLg = bp.between('lg', 'xl'); // 1024px - 1280px + const isXl = bp.between('xl', 'xxl'); // 1280px - 1536px + const isXxl = bp.greater('xxl'); // > 1536px + + // 监听窗口变化 + const { width, height } = useWindowSize(); + + // 方向检测 + const isPortrait = computed(() => height.value > width.value); + const isLandscape = computed(() => width.value > height.value); + + // 当前断点名称 + const currentBreakpoint = computed(() => { + if (isXs.value) return 'xs'; + if (isSm.value) return 'sm'; + if (isMd.value) return 'md'; + if (isLg.value) return 'lg'; + if (isXl.value) return 'xl'; + return 'xxl'; + }); + + return { + // 设备类型 + isMobile, + isTablet, + isDesktop, + + // 精确断点 + isXs, + isSm, + isMd, + isLg, + isXl, + isXxl, + + // 尺寸 + width, + height, + + // 方向 + isPortrait, + isLandscape, + + // 当前断点名称 + currentBreakpoint, + }; +} diff --git a/Yi.Ai.Vue3/src/hooks/useWindowWidthObserver.ts b/Yi.Ai.Vue3/src/hooks/useWindowWidthObserver.ts index a5c4bc52..5adf34b3 100644 --- a/Yi.Ai.Vue3/src/hooks/useWindowWidthObserver.ts +++ b/Yi.Ai.Vue3/src/hooks/useWindowWidthObserver.ts @@ -19,8 +19,9 @@ export function useWindowWidthObserver( const isAboveThreshold = ref(false); const thresholdRef = ref(threshold); let prevIsAbove = false; // 记录上一次状态,避免重复触发 - + // 待定 待梳理 1227 // 默认逻辑:修改全局折叠状态 + // eslint-disable-next-line unused-imports/no-unused-vars const updateCollapseState = (isAbove: boolean) => { // 判断当前的折叠状态 switch (designStore.collapseType) { @@ -70,7 +71,7 @@ export function useWindowWidthObserver( onChange(newIsAbove); } else { - updateCollapseState(newIsAbove); + // updateCollapseState(newIsAbove); } } }; diff --git a/Yi.Ai.Vue3/src/layouts/LayoutDefault/index.vue b/Yi.Ai.Vue3/src/layouts/LayoutDefault/index.vue new file mode 100644 index 00000000..cb358436 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/LayoutDefault/index.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/LayoutMobile/index.vue b/Yi.Ai.Vue3/src/layouts/LayoutMobile/index.vue index 29fc25ab..60d7f8dd 100644 --- a/Yi.Ai.Vue3/src/layouts/LayoutMobile/index.vue +++ b/Yi.Ai.Vue3/src/layouts/LayoutMobile/index.vue @@ -1,8 +1,288 @@ - - + + - + diff --git a/Yi.Ai.Vue3/src/layouts/LayoutVertical/index.vue b/Yi.Ai.Vue3/src/layouts/LayoutVertical/index.vue index 32264f60..5d752ac4 100644 --- a/Yi.Ai.Vue3/src/layouts/LayoutVertical/index.vue +++ b/Yi.Ai.Vue3/src/layouts/LayoutVertical/index.vue @@ -2,8 +2,6 @@ - - - - diff --git a/Yi.Ai.Vue3/src/layouts/components/ChatAside/index.vue b/Yi.Ai.Vue3/src/layouts/components/ChatAside/index.vue new file mode 100644 index 00000000..c0e8710d --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components/ChatAside/index.vue @@ -0,0 +1,918 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components/Header/components/Avatar.vue b/Yi.Ai.Vue3/src/layouts/components/Header/components/Avatar.vue index 26675ad5..0b98e38e 100644 --- a/Yi.Ai.Vue3/src/layouts/components/Header/components/Avatar.vue +++ b/Yi.Ai.Vue3/src/layouts/components/Header/components/Avatar.vue @@ -30,40 +30,40 @@ const popoverRef = ref(); // 弹出面板内容 const popoverList = ref([ - { - key: '5', - title: '控制台', - icon: 'settings-4-fill', - }, - { - key: '3', - divider: true, - }, - { - key: '7', - title: '公告', - icon: 'notification-fill', - }, - { - key: '8', - title: '模型库', - icon: 'apps-fill', - }, - { - key: '9', - title: '文档', - icon: 'book-fill', - }, - - { - key: '6', - title: '新手引导', - icon: 'dashboard-fill', - }, - { - key: '3', - divider: true, - }, + // { + // key: '5', + // title: '控制台', + // icon: 'settings-4-fill', + // }, + // { + // key: '3', + // divider: true, + // }, + // { + // key: '7', + // title: '公告', + // icon: 'notification-fill', + // }, + // { + // key: '8', + // title: '模型库', + // icon: 'apps-fill', + // }, + // { + // key: '9', + // title: '文档', + // icon: 'book-fill', + // }, + // + // { + // key: '6', + // title: '新手引导', + // icon: 'dashboard-fill', + // }, + // { + // key: '3', + // divider: true, + // }, { key: '4', title: '退出登录', @@ -130,7 +130,9 @@ function handleClick(item: any) { ElMessage.warning('暂未开放'); break; case '5': - openDialog(); + // 打开控制台 + popoverRef.value?.hide?.(); + router.push('/console'); break; case '6': handleStartTutorial(); diff --git a/Yi.Ai.Vue3/src/layouts/components/Header/components/StartChatBtn.vue b/Yi.Ai.Vue3/src/layouts/components/Header/components/StartChatBtn.vue new file mode 100644 index 00000000..970e1509 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components/Header/components/StartChatBtn.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components/Header/components/ThemeBtn.vue b/Yi.Ai.Vue3/src/layouts/components/Header/components/ThemeBtn.vue new file mode 100644 index 00000000..975fd521 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components/Header/components/ThemeBtn.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components/Header/index.vue b/Yi.Ai.Vue3/src/layouts/components/Header/index.vue index aaacdec3..1db0ae27 100644 --- a/Yi.Ai.Vue3/src/layouts/components/Header/index.vue +++ b/Yi.Ai.Vue3/src/layouts/components/Header/index.vue @@ -1,94 +1,50 @@ - + -
- - -
-
- - -
- -
-
+
+ <!– 左侧logo和品牌区域 –> +
+
+ + 意心AI
+
- -
- - - - - - - -
+ <!– 右侧功能按钮区域 –> +
+ + + + + + + + +
@@ -98,20 +54,483 @@ function handleOpenConsole() { .header-container { display: flex; flex-shrink: 0; - flex-direction: column; width: 100%; - height: fit-content; + height: var(--header-container-default-height, 60px); + .header-box { + display: flex; + align-items: center; + justify-content: space-between; width: 100%; - width: calc( - 100% - var(--sidebar-left-container-default-width, 0px) - var( - --sidebar-right-container-default-width, - 0px - ) - ); - height: var(--header-container-default-heigth); - margin: 0 var(--sidebar-right-container-default-width, 0) 0 - var(--sidebar-left-container-default-width, 0); + height: 100%; + padding: 0 16px; + background: var(--header-bg-color, #ffffff); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); + } + + // 左侧品牌区域 + .left-section { + display: flex; + align-items: center; + min-width: fit-content; + flex-shrink: 0; + + .brand-container { + display: flex; + align-items: center; + gap: 8px; + + .logo-img { + width: 36px; // 优化为更合适的大小 + height: 36px; + flex-shrink: 0; + transition: transform 0.2s ease; + + &:hover { + transform: scale(1.05); + } + } + + .brand-text { + font-size: 22px; // 减小字体大小 + font-weight: bold; + color: var(--brand-color, #000000); + white-space: nowrap; + letter-spacing: -0.5px; + transition: color 0.2s ease; + + &:hover { + //color: var(--brand-hover-color, #40a9ff); + } + } + } + } + + // 右侧功能区域 + .right-section { + display: flex; + align-items: center; + gap: 12px; // 优化按钮间距 + height: 100%; + flex-shrink: 0; + + // 统一按钮样式 + :deep(.menu-button) { + height: 36px; + display: flex; + align-items: center; + justify-content: center; + } + } +} + +--> + + + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Aside/index.vue b/Yi.Ai.Vue3/src/layouts/components0/Aside/index.vue new file mode 100644 index 00000000..be93e273 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Aside/index.vue @@ -0,0 +1,725 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/DesignConfig/index.vue b/Yi.Ai.Vue3/src/layouts/components0/DesignConfig/index.vue new file mode 100644 index 00000000..f3409aa6 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/DesignConfig/index.vue @@ -0,0 +1,8 @@ + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/AiTutorialBtn.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/AiTutorialBtn.vue new file mode 100644 index 00000000..bd7f2647 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/AiTutorialBtn.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/AnnouncementBtn.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/AnnouncementBtn.vue new file mode 100644 index 00000000..a6c6adda --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/AnnouncementBtn.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/Avatar.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/Avatar.vue new file mode 100644 index 00000000..7f1ed3c1 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/Avatar.vue @@ -0,0 +1,499 @@ + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/BuyBtn.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/BuyBtn.vue new file mode 100644 index 00000000..9e5b512a --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/BuyBtn.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/Collapse.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/Collapse.vue new file mode 100644 index 00000000..9868df5d --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/Collapse.vue @@ -0,0 +1,39 @@ + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/ConsoleBtn.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/ConsoleBtn.vue new file mode 100644 index 00000000..3091d22e --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/ConsoleBtn.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/CreateChat.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/CreateChat.vue new file mode 100644 index 00000000..5ec82222 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/CreateChat.vue @@ -0,0 +1,45 @@ + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/LoginBtn.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/LoginBtn.vue new file mode 100644 index 00000000..64b43c4c --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/LoginBtn.vue @@ -0,0 +1,29 @@ + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/ModelLibraryBtn.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/ModelLibraryBtn.vue new file mode 100644 index 00000000..73347ac9 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/ModelLibraryBtn.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/StartChatBtn.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/StartChatBtn.vue new file mode 100644 index 00000000..970e1509 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/StartChatBtn.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/ThemeBtn.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/ThemeBtn.vue new file mode 100644 index 00000000..975fd521 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/ThemeBtn.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/TitleEditing.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/TitleEditing.vue new file mode 100644 index 00000000..767e2d53 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/TitleEditing.vue @@ -0,0 +1,87 @@ + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/components/TutorialBtn.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/components/TutorialBtn.vue new file mode 100644 index 00000000..524ae1cd --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/components/TutorialBtn.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Header/index.vue b/Yi.Ai.Vue3/src/layouts/components0/Header/index.vue new file mode 100644 index 00000000..d8dc7806 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Header/index.vue @@ -0,0 +1,122 @@ + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Logo/index.vue b/Yi.Ai.Vue3/src/layouts/components0/Logo/index.vue new file mode 100644 index 00000000..a84746fd --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Logo/index.vue @@ -0,0 +1,8 @@ + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/components0/Main/index.vue b/Yi.Ai.Vue3/src/layouts/components0/Main/index.vue new file mode 100644 index 00000000..59622a62 --- /dev/null +++ b/Yi.Ai.Vue3/src/layouts/components0/Main/index.vue @@ -0,0 +1,89 @@ + + + + + + diff --git a/Yi.Ai.Vue3/src/layouts/index.vue b/Yi.Ai.Vue3/src/layouts/index.vue index ed682c5e..50a80f49 100644 --- a/Yi.Ai.Vue3/src/layouts/index.vue +++ b/Yi.Ai.Vue3/src/layouts/index.vue @@ -1,21 +1,41 @@ + + + + diff --git a/Yi.Ai.Vue3/src/pages/chat/conversation/index.vue b/Yi.Ai.Vue3/src/pages/chat/conversation/index.vue new file mode 100644 index 00000000..815896e9 --- /dev/null +++ b/Yi.Ai.Vue3/src/pages/chat/conversation/index.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/pages/chat/image/index.vue b/Yi.Ai.Vue3/src/pages/chat/image/index.vue new file mode 100644 index 00000000..b319c725 --- /dev/null +++ b/Yi.Ai.Vue3/src/pages/chat/image/index.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/pages/chat/index.vue b/Yi.Ai.Vue3/src/pages/chat/index.vue index 933c9a65..82619c11 100644 --- a/Yi.Ai.Vue3/src/pages/chat/index.vue +++ b/Yi.Ai.Vue3/src/pages/chat/index.vue @@ -1,31 +1,304 @@ - diff --git a/Yi.Ai.Vue3/src/pages/chat/layouts/chatDefaul/index.vue b/Yi.Ai.Vue3/src/pages/chat/layouts/chatDefaul/index.vue index 44180051..2ec17b1c 100644 --- a/Yi.Ai.Vue3/src/pages/chat/layouts/chatDefaul/index.vue +++ b/Yi.Ai.Vue3/src/pages/chat/layouts/chatDefaul/index.vue @@ -7,162 +7,259 @@ import { ElMessage } from 'element-plus'; import { nextTick, ref, watch } from 'vue'; import ModelSelect from '@/components/ModelSelect/index.vue'; import WelecomeText from '@/components/WelecomeText/index.vue'; -import { useGuideTourStore, useUserStore } from '@/stores'; +import { useUserStore } from '@/stores'; import { useFilesStore } from '@/stores/modules/files'; - import { useSessionStore } from '@/stores/modules/session'; +// Store 实例 const userStore = useUserStore(); const sessionStore = useSessionStore(); const filesStore = useFilesStore(); -const guideTourStore = useGuideTourStore(); -const senderValue = ref(''); -const senderRef = ref(); +// 响应式数据 +const senderValue = ref(''); // 输入框内容 +const senderRef = ref(); // Sender 组件引用 const isSending = ref(false); // 发送状态标志 -// 防抖发送函数 -const debouncedSend = useDebounceFn(async () => { - if (!senderValue.value.trim()) { - ElMessage.warning('消息内容不能为空'); - return; - } +/** + * 防抖发送消息函数 + */ +const debouncedSend = useDebounceFn( + async () => { + // 1. 验证输入 + if (!senderValue.value.trim()) { + ElMessage.warning('消息内容不能为空'); + return; + } - if (isSending.value) { - ElMessage.warning('请等待上一条消息发送完成'); - return; - } + // 2. 检查是否正在发送 + if (isSending.value) { + ElMessage.warning('请等待上一条消息发送完成'); + return; + } - const content = senderValue.value; - isSending.value = true; + // 3. 准备发送数据 + const content = senderValue.value.trim(); + isSending.value = true; - try { - localStorage.setItem('chatContent', content); - await sessionStore.createSessionList({ - userId: userStore.userInfo?.userId as number, - sessionContent: content, - sessionTitle: content.slice(0, 10), - remark: content.slice(0, 10), - }); - senderValue.value = ''; // 清空输入框 - } - catch (error: any) { - console.error('发送消息失败:', error); - ElMessage.error(error); - } - finally { - isSending.value = false; - } -}, 800, { leading: true, trailing: false }); // 800ms防抖 + try { + // 4. 保存到本地存储(可选,用于页面刷新后恢复) + localStorage.setItem('chatContent', content); -// 处理发送事件 + // 5. 创建会话 + await sessionStore.createSessionList({ + userId: userStore.userInfo?.userId as number, + sessionContent: content, + sessionTitle: content.slice(0, 10), + remark: content.slice(0, 10), + }); + + // 6. 清空输入框 + senderValue.value = ''; + } + catch (error: any) { + console.error('发送消息失败:', error); + ElMessage.error(error.message || '发送消息失败'); + } + finally { + // 7. 重置发送状态 + isSending.value = false; + } + }, + 800, // 防抖延迟 + { leading: true, trailing: false }, // 立即执行第一次,忽略后续快速点击 +); + +/** + * 触发发送消息 + */ function handleSend() { debouncedSend(); } +/** + * 删除文件卡片 + * @param _item 文件项 + * @param index 文件索引 + */ function handleDeleteCard(_item: FilesCardProps, index: number) { filesStore.deleteFileByIndex(index); } +/** + * 监听文件列表变化,自动展开/收起 Sender 头部 + */ watch( () => filesStore.filesList.length, (val) => { - if (val > 0) { - nextTick(() => { + nextTick(() => { + if (val > 0) { senderRef.value?.openHeader(); - }); - } - else { - nextTick(() => { + } + else { senderRef.value?.closeHeader(); - }); - } + } + }); }, ); diff --git a/Yi.Ai.Vue3/src/pages/chat/layouts/chatWithId/index.vue b/Yi.Ai.Vue3/src/pages/chat/layouts/chatWithId/index.vue index 0ecb2ee1..fd6d0046 100644 --- a/Yi.Ai.Vue3/src/pages/chat/layouts/chatWithId/index.vue +++ b/Yi.Ai.Vue3/src/pages/chat/layouts/chatWithId/index.vue @@ -562,14 +562,16 @@ function handleImagePreview(url: string) { diff --git a/Yi.Ai.Vue3/src/pages/console/index.vue b/Yi.Ai.Vue3/src/pages/console/index.vue new file mode 100644 index 00000000..44aece8f --- /dev/null +++ b/Yi.Ai.Vue3/src/pages/console/index.vue @@ -0,0 +1,313 @@ + + + + + diff --git a/Yi.Ai.Vue3/src/pages/modelLibrary/index.vue b/Yi.Ai.Vue3/src/pages/modelLibrary/index.vue index df8dc070..264aeb12 100644 --- a/Yi.Ai.Vue3/src/pages/modelLibrary/index.vue +++ b/Yi.Ai.Vue3/src/pages/modelLibrary/index.vue @@ -266,6 +266,7 @@ onMounted(() => {
{