Forráskód Böngészése

添加大运河和植物专家

丸子 3 hónapja
szülő
commit
8f1fefb71d

BIN
src/assets/icon/canal.png


BIN
src/assets/icon/canal02.png


BIN
src/assets/icon/plant.png


BIN
src/assets/icon/plant02.png


BIN
src/assets/images/farm.png


+ 98 - 65
src/components/LeftPanel.vue

@@ -7,7 +7,7 @@
           <el-menu
             :default-active="currentActiveIndex"
             class="el-menu-vertical-demo"
-            @open="handleOpen"  
+            @open="handleOpen"
             @close="handleClose"
           >
             <el-menu-item
@@ -15,12 +15,11 @@
               :key="index"
               :index="index.toString()"
               @click="navigateToAI(item)"
-              v-model="currentActiveIndex"
               @mouseover="item.isHover = true"
               @mouseout="item.isHover = false"
             >
               <!-- 根据状态切换图片-->
-               <img
+              <img
                 :src="currentActiveIndex === index.toString() || item.isHover ? item.hoverIcon : item.icon"
                 alt=""
                 class="menu-icon"
@@ -35,12 +34,12 @@
 </template>
 
 <script setup>
-import { ref, onMounted,watch} from 'vue'
+import { ref, onMounted, watch } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import { teacherList } from '@/api/teachers.js'
 
-
-// 导入图片 白色
+// 导入图片
+// 白色图标
 import question from '@/assets/icon/question.png'
 import painting from '@/assets/icon/painting.png'
 import Human from '@/assets/icon/human.png'
@@ -48,8 +47,11 @@ import image2image from '@/assets/icon/image2image.png'
 import video from '@/assets/icon/video.png'
 import labImage from '@/assets/icon/labImage.png'
 import en from '@/assets/icon/en.png'
-import avatar from '@/assets/icon/avatar.png'
-// 黑色
+import canal from '@/assets/icon/canal.png'
+import plant from '@/assets/icon/plant.png'
+
+
+// 黑色图标
 import question02 from '@/assets/icon/question02.png'
 import painting02 from '@/assets/icon/painting02.png'
 import Human02 from '@/assets/icon/Human02.png'
@@ -57,10 +59,9 @@ import image2image02 from '@/assets/icon/image2image02.png'
 import video02 from '@/assets/icon/video02.png'
 import labImage02 from '@/assets/icon/labImage02.png'
 import en02 from '@/assets/icon/en02.png'
-import avatar02 from '@/assets/icon/avatar02.png'
-
+import canal02 from '@/assets/icon/canal02.png'
+import plant02 from '@/assets/icon/plant02.png'
 
- 
 const router = useRouter()
 const route = useRoute()
 
@@ -69,6 +70,32 @@ const drawerVisible = ref(true)
 // 当前选中索引状态
 const currentActiveIndex = ref('2')
 
+// 路由路径到索引的映射
+const pathIndexMap = {
+  'ai-questions': '0',      // 智能问答
+  'ai-painting': '1',       // 智能绘画
+  'ai-laboratory': '2',     // 数字人老师
+  'ai-ennumerals': '3',     // 英文数字人老师
+  'ai-image': '4',          // 图生图
+  'ai-video': '5',          // 图生视频
+  'ai-grandcanal': '6',     // 大运河
+  'ai-plantexperts': '7',   // 植物专家
+  'virtual-laboratory': '8' // 虚拟实验室
+}
+
+// 菜单项到路由的映射
+const menuRouteMap = {
+  '智能问答': '/ai-questions',
+  '智能绘画': '/ai-painting',
+  '数字人老师': '/ai-laboratory',
+  '英文数字人老师': '/ai-ennumerals',
+  '图生图': '/ai-image',
+  '图生视频': '/ai-video',
+  '大运河': '/ai-grandcanal',
+  '植物专家': '/ai-plantexperts',
+  '虚拟实验室': '/virtual-laboratory'
+}
+
 // 渲染侧边栏
 const groupList = ref([
   {
@@ -101,6 +128,16 @@ const groupList = ref([
     hoverIcon: video02,
     title: '图生视频'
   },
+  {
+    icon: canal,
+    hoverIcon: canal02,
+    title: '大运河'
+  },
+  {
+    icon: plant,
+    hoverIcon: plant02,
+    title: '植物专家'
+  },
   {
     icon: labImage,
     hoverIcon: labImage02,
@@ -108,56 +145,49 @@ const groupList = ref([
   }
 ])
 
-
-// 提取更新选中状态的逻辑为单独函数
-// 优化后的更新选中状态的方法
+// 更新选中状态的方法
 const updateActiveIndex = () => {
-  const path = route.path;
-  const from = window.history.state?.from; // 从history.state获取来源信息
-  // 使用映射表存储路径和索引的对应关系
-  const pathIndexMap = {
-    'ai-questions': '0', // 智能问答
-    'ai-painting': '1',  // 智能绘画
-    'ai-laboratory': '2', // 数字人老师
-    'ai-ennumerals': '3', // 英文数字人老师
-    'ai-image': '4' ,     // 图生图
-    'ai-video': '5' ,     // 图生视频
-    'virtual-laboratory':"6",// 虚拟实验室
-    
-  };
+  const path = route.path
+  const from = window.history.state?.from // 从history.state获取来源信息
+  
   // 从数字人老师页面进入智能问答页面
   if (path.includes('ai-questions') && from === 'ai-laboratory') {
-    currentActiveIndex.value = '2'; // 保持选中数字人老师
-    return;
+    currentActiveIndex.value = '2' // 保持选中数字人老师
+    return
   }
-   // 从英文数字人老师页面进入智能问答页面
+  
+  // 从英文数字人老师页面进入智能问答页面
   if (path.includes('ai-questions') && from === 'ai-ennumerals') {
-    currentActiveIndex.value = '3'; // 保持选中英文数字人老师
-    return;
+    currentActiveIndex.value = '3' // 保持选中英文数字人老师
+    return
   }
+  
   // 查找路径对应的索引
   for (const [key, index] of Object.entries(pathIndexMap)) {
     if (path.includes(key)) {
-      currentActiveIndex.value = index;
-      return;
+      currentActiveIndex.value = index
+      return
     }
   }
-};
+}
 
 // 组件挂载时确保默认选中状态
 onMounted(() => {
-  updateActiveIndex();
-});
+  updateActiveIndex()
+})
 
 // 添加路由变化监听,更新选中状态
-watch(() => route, () => {
-  updateActiveIndex();
-}, { immediate: true, deep: true });
+watch(() => route.path, () => {
+  updateActiveIndex()
+}, { immediate: true })
 
 // 存储小智数据
 const personData = ref([])
+
 // 跳转智能问答
 const navigateToAI = async (group) => {
+  const routePath = menuRouteMap[group.title]
+  
   if (group.title === '智能问答') {
     try {
       const grade = route.query.grade || localStorage.getItem('selectedGrade')
@@ -166,6 +196,7 @@ const navigateToAI = async (group) => {
       const aiPerson = juniorAIRes.data.list.find(
         person => person.name === '小智'
       )
+      
       if (aiPerson) {
         personData.value = {
           id: aiPerson.id,
@@ -174,44 +205,32 @@ const navigateToAI = async (group) => {
           message: aiPerson.systemMessage,
           default: aiPerson.questTip
         }
-        let newState = {
+        
+        const newState = {
           ...personData.value,
           category: grade + 'AI'
         }
+        
         // 先 push 再手动更新 history.state(确保原生 state 同步)
         router
           .push({
-            path: '/ai-questions',
+            path: routePath,
             state: newState
-          }).then(() => {
+          })
+          .then(() => {
             // 手动替换当前历史记录的 state 为最新值
-          window.history.replaceState(newState, '', window.location.href)
-          window.location.reload()
-        })
+            window.history.replaceState(newState, '', window.location.href)
+            window.location.reload()
+          })
       } else {
         console.warn('未找到名为小智的数据')
       }
     } catch (error) {
       console.error('获取小学低年级AI数据失败:', error)
     }
-  }
-  if (group.title === '智能绘画') {
-    router.push('/ai-painting')
-  }
-  if (group.title === '数字人老师') {
-    router.push('/ai-laboratory')
-  }
-   if (group.title === '英文数字人老师') {
-    router.push('/ai-ennumerals')
-  }
-  if (group.title === '图生图') {
-    router.push('/ai-image')
-  }
-  if (group.title === '图生视频') {
-    router.push('/ai-video')
-  }
-  if (group.title === '虚拟实验室') {
-    router.push('/virtual-laboratory')
+  } else {
+    // 其他菜单项直接跳转
+    router.push(routePath)
   }
 }
 
@@ -223,22 +242,25 @@ const handleClose = () => {}
 defineExpose({
   drawerVisible,
   toggleDrawer: () => {
-    drawerVisible.value = !drawerVisible.value 
+    drawerVisible.value = !drawerVisible.value
   }
 })
 </script>
 
 <style scoped lang="scss">
 @use 'sass:math';
+
 // 定义rpx转换函数
 @function rpx($px) {
   @return math.div($px, 750) * 100vw;
 }
+
 /* 添加过渡样式 */
 ::v-deep .drawer-slide-enter-active,
 ::v-deep .drawer-slide-leave-active {
   transition: all 0.3s ease;
 }
+
 ::v-deep .drawer-slide-enter-from,
 ::v-deep .drawer-slide-leave-to {
   transform: translateX(-100%);
@@ -251,27 +273,33 @@ defineExpose({
   height: 100%;
   background: linear-gradient(to bottom, #001169, #8a78d0);
   overflow-y: auto;
+  
   // 自定义滚动条样式
   &::-webkit-scrollbar {
     width: rpx(0); // 滚动条宽度
   }
+  
   &::-webkit-scrollbar-track {
     background-color: rgba(255, 255, 255, 0.1); // 滚动条轨道背景色
     border-radius: rpx(2); // 滚动条轨道圆角
   }
+  
   &::-webkit-scrollbar-thumb {
     background-color: rgba(255, 255, 255, 0.3); // 滚动条滑块颜色
     border-radius: rpx(2); // 滚动条滑块圆角
     transition: background-color 0.3s ease; // 滑块颜色过渡效果
   }
+  
   &::-webkit-scrollbar-thumb:hover {
     background-color: rgba(255, 255, 255, 0.5); // 鼠标悬停时的滑块颜色
   }
 }
+
 .mb-2 {
   color: black;
   margin-top: rpx(1);
 }
+
 .tac ::v-deep(.el-menu) {
   background-color: transparent;
   border: none;
@@ -279,6 +307,7 @@ defineExpose({
   margin-top: rpx(25);
   margin-left: rpx(10);
 }
+
 .el-menu-item {
   width: rpx(115);
   height: rpx(25);
@@ -287,22 +316,26 @@ defineExpose({
   color: white;
   font-size: rpx(8);
 }
+
 .el-menu-item .el-icon svg {
   font-size: rpx(15);
   color: white;
 }
+
 .el-menu .el-menu-item:hover {
   background: linear-gradient(to bottom, #ffefb0, #ffcc00);
   box-shadow: 0 8px 8px rgb(0, 0, 0, 0.3);
   color: black;
   font-size: rpx(8);
 }
+
 :deep(.el-menu .el-menu-item.is-active) {
   background: linear-gradient(to bottom, #fee78a, #ffce1b);
   color: black;
   font-size: rpx(8);
   box-shadow: 0 4px 8px rgba(3, 3, 3, 0.3);
 }
+
 .menu-icon {
   width: rpx(11);
   height: rpx(11);

+ 7 - 0
src/components/ai/text/TextToText.vue

@@ -974,5 +974,12 @@ defineExpose({
   border-radius: rpx(5);
   cursor: pointer;
   box-shadow: 0 0px 2px rgba(0, 0, 0, 0.3);
+  
+  // 取消点击后的边框
+  &:focus,
+  &:focus-visible {
+    outline: none;
+    box-shadow: 0 0px 2px rgba(0, 0, 0, 0.3);
+  }
 }
 </style>

+ 10 - 1
src/components/ai/voice/VoiceInput.vue

@@ -73,6 +73,8 @@ const initSpeechRecognition = () => {
       const transcript = event.results[i][0].transcript
       // 无论是否是最终结果,实时识别结果
       emit('voiceRecognized', transcript)
+      // 打印语音识别结果
+      console.log('语音输入文字:', transcript)
     }
   }
 
@@ -174,6 +176,13 @@ onUnmounted(() => {
   align-items: center;
   gap: rpx(4);
 
+  // 取消点击后的边框
+  &:focus,
+  &:focus-visible {
+    outline: none;
+    box-shadow: none;
+  }
+
   &.recording {
     background: #ffeeba;
     border-color: #ffc107;
@@ -190,7 +199,7 @@ onUnmounted(() => {
 }
 .waveform-container {
   // width: 100%;
-  max-width: rpx(40);
+  max-width: rpx(30);
 }
 .countdown-text {
   font-size: rpx(6);

+ 36 - 16
src/components/videopage/DialogComponents.vue

@@ -114,12 +114,14 @@
           >
           <!-- 语音输入 -->
               <template #prepend>
-               <VoiceInput
-                 @voiceRecognized="handleVoiceRecognized"
-                 @recordingStatusChanged="handleRecordingStatusChanged"
-                 lang="zh-CN"
-                 maxDuration="10"
-               />
+               <div class="voice-input-wrapper">
+                 <VoiceInput
+                   @voiceRecognized="handleVoiceRecognized"
+                   @recordingStatusChanged="handleRecordingStatusChanged"
+                   lang="zh-CN"
+                   maxDuration="10"
+                 />
+               </div>
               </template>
 
             <!-- 终止按钮和发送按钮条件渲染 -->
@@ -1052,8 +1054,8 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
   
   // 语音按钮样式
   ::v-deep(.el-input-group__prepend) {
-    width: rpx(25); // 非录音状态的默认宽度
-    min-width: rpx(25);
+    width: auto;
+    min-width: unset;
     background: white;
     border-radius: rpx(5);
     text-align: center;
@@ -1064,20 +1066,29 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
   // 录音状态下的样式
   ::v-deep(.el-input-group__prepend) {
     &.recording {
-      width: rpx(60); // 录音状态下增加宽度
-      min-width: rpx(60);
+      width: auto;
+      min-width: unset;
     }
   }
   
-  ::v-deep(.el-input-group__prepend .el-button.recording) {
-    padding: rpx(5) rpx(10);
-    background: #fff;
+  // 语音输入容器样式,使其宽高和发送按钮一致
+  .voice-input-wrapper {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: 100%;
+  }
+  
+  // 语音按钮样式,使其宽高和发送按钮一致
+  ::v-deep(.voice-input-wrapper .speech-btn) {
+    height: rpx(23);
+    padding: 0 rpx(10);
     border: none;
     border-radius: rpx(5);
-    cursor: pointer;
+    background: white;
     display: flex;
     align-items: center;
-    color: #dc3545;
+    justify-content: center;
   }
   
   ::v-deep(.el-input-group__append) {
@@ -1085,8 +1096,17 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
     background: linear-gradient(to bottom, #ab81ff, #8559dc);
     border-radius: rpx(5);
     color: white;
-    font-size: rpx(9);
+    font-size: rpx(8);
     border-left: none;
+    height: rpx(23);
+    padding: rpx(0) rpx(7);
+    
+    // 取消点击后的边框
+    &:focus,
+    &:focus-visible {
+      outline: none;
+      box-shadow: none;
+    }
   }
 }
 

+ 12 - 0
src/router/index.js

@@ -74,6 +74,16 @@ const routes = [
   {
     path: '/ai-video',
     component: () => import('../views/AIPage/AIImageToVideo.vue')
+  },
+    // 大运河
+  {
+    path: '/ai-grandcanal',
+    component: () => import('../views/AIPage/GrandCanal.vue')
+  },
+  // 植物专家
+    {
+    path: '/ai-plantexperts',
+    component: () => import('../views/AIPage/PlantExperts.vue')
   },
   // 智能问答
   {
@@ -161,6 +171,8 @@ const homeRoutes = {
     '/ai-video',
     '/ai-questions',
     '/ai-develop',
+    '/ai-grandcanal',
+    '/ai-plantexperts',
     '/virtual-laboratory'
   ]
 }

+ 4 - 4
src/views/AIPage/AIAvatar.vue

@@ -149,10 +149,10 @@ const goBack = () => {
   cursor: pointer; // 添加鼠标指针样式
 }
 
-.box-icon .left-icon {
-  margin-left: rpx(10);
-  margin-right: rpx(5); // 设置图标和文字之间的间距 ;
-}
+// .box-icon .left-icon {
+//   margin-left: rpx(10);
+//   margin-right: rpx(5); // 设置图标和文字之间的间距 ;
+// }
 
 .img-box {
   margin-top: rpx(50);

+ 4 - 4
src/views/AIPage/AIDevelop.vue

@@ -956,10 +956,10 @@ $text-color: #483d8b; // 文本颜色:靛蓝色
   padding-left: rpx(15);
   font-size: rpx(10); // 设置图标大小,可按需调整
 }
-.box-icon .left-icon {
-  margin-left: rpx(10);
-  margin-right: rpx(5); // 设置图标和文字之间的间距 ;
-}
+// .box-icon .left-icon {
+//   margin-left: rpx(10);
+//   margin-right: rpx(5); // 设置图标和文字之间的间距 ;
+// }
 
 .left-box span {
   position: absolute;

+ 4 - 4
src/views/AIPage/AIGeneralCourse.vue

@@ -629,10 +629,10 @@ const goToAIExperience = outlineData => {
   cursor: pointer; // 鼠标指针样式
   z-index: 999;
 }
-.box-icon .left-icon {
-  margin-left: rpx(10);
-  margin-right: rpx(5); // 设置图标和文字之间的间距 ;
-}
+// .box-icon .left-icon {
+//   margin-left: rpx(10);
+//   margin-right: rpx(5); // 设置图标和文字之间的间距 ;
+// }
 
 .left-box span {
   position: absolute;

+ 4 - 4
src/views/AIPage/AIImageToImage.vue

@@ -149,10 +149,10 @@ const goBack = () => {
   cursor: pointer; // 添加鼠标指针样式
 }
 
-.box-icon .left-icon {
-  margin-left: rpx(10);
-  margin-right: rpx(5); // 设置图标和文字之间的间距 ;
-}
+// .box-icon .left-icon {
+//   margin-left: rpx(10);
+//   margin-right: rpx(5); // 设置图标和文字之间的间距 ;
+// }
 
 .img-box {
   margin-top: rpx(50);

+ 4 - 4
src/views/AIPage/AIImageToVideo.vue

@@ -144,10 +144,10 @@ const toggleDrawer = () => {
   cursor: pointer;
 }
 
-.box-icon .left-icon {
-  margin-left: rpx(10);
-  margin-right: rpx(5);
-}
+// .box-icon .left-icon {
+//   margin-left: rpx(10);
+//   margin-right: rpx(5);
+// }
 
 .img-box {
   margin-top: rpx(50);

+ 4 - 4
src/views/AIPage/AILaboratory.vue

@@ -272,10 +272,10 @@ const groupList = ref([
   font-size: rpx(10); // 设置图标大小,可按需调整
   cursor: pointer; // 添加鼠标指针样式
 }
-.box-icon .left-icon {
-  margin-left: rpx(10);
-  margin-right: rpx(5); // 设置图标和文字之间的间距 ;
-}
+// .box-icon .left-icon {
+//   margin-left: rpx(10);
+//   margin-right: rpx(5); // 设置图标和文字之间的间距 ;
+// }
 // 内容样式
 .content-box {
   // width: 100%;

+ 4 - 4
src/views/AIPage/AIPainting.vue

@@ -217,10 +217,10 @@ const toggleDrawer = () => {
   font-size: rpx(10); // 设置图标大小,可按需调整
   cursor: pointer; // 添加鼠标指针样式
 }
-.box-icon .left-icon {
-  margin-left: rpx(10);
-  margin-right: rpx(5); // 设置图标和文字之间的间距 ;
-}
+// .box-icon .left-icon {
+//   margin-left: rpx(10);
+//   margin-right: rpx(5); // 设置图标和文字之间的间距 ;
+// }
 
 //左侧展览区图标
 .img-box {

+ 2 - 2
src/views/AIPage/AIQuestions.vue

@@ -175,7 +175,7 @@ watch(
 }
 
 .box-icon .left-icon {
-  margin-left: rpx(10);
-  margin-right: rpx(5);
+  margin-left: rpx(0);
+  margin-right: rpx(0);
 }
 </style>

+ 172 - 0
src/views/AIPage/GrandCanal.vue

@@ -0,0 +1,172 @@
+<template>
+  <!-- 数字人智能问答 -->
+  <div class="home-container">
+    <!-- 展开收起侧边栏 -->
+    <div
+      class="icon-expand"
+      :style="{
+        backgroundColor: drawerVisible ? '#44449c' : '#7F70C840',
+        left: drawerVisible ? '18%' : '0',
+      }"
+      @click="toggleDrawer"
+    >
+      <span
+        class="vertical-lines"
+        :style="{
+          color: drawerVisible ? '#8a78d0' : 'white',
+        }"
+        >||</span
+      >
+    </div>
+
+    <!-- 左侧折叠面板 -->
+    <LeftPanel ref="leftPanelRef" v-if="drawerVisible" />
+
+    <!-- 原左侧折叠面板和右侧AI问答 --> 
+    <div class="content-wrapper">
+      <div class="left-group2">
+        <div class="title-box">
+          <div class="box-icon" @click="goBack">
+            <el-icon class="left-icon"><ArrowLeftBold /></el-icon>
+            返回首页 | 大运河
+          </div>
+        </div>
+      </div>
+      
+      <TextToText
+        :personId="personId"
+        :personName="personName"
+        :personImage="personImage"
+        :personIntroduce="personIntroduce"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted, watch } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import LeftPanel from "@/components/LeftPanel.vue";
+import { ArrowLeftBold } from "@element-plus/icons-vue";
+import TextToText from "@/components/ai/text/TextToText.vue";
+import {homeRoutes} from "@/router/index.js";
+
+const leftPanelRef = ref(null);
+
+// 抽屉显示状态
+const drawerVisible = ref(true);
+
+// 添加切换抽屉显示状态的函数
+const toggleDrawer = () => {
+  drawerVisible.value = !drawerVisible.value;
+};
+
+// 返回首页
+const goBack = () => {
+    router.push(homeRoutes.home);
+};
+
+const router = useRouter();
+const route = useRoute();
+
+// 从history.state获取参数
+const personId = ref(window.history.state?.id || '');
+const personName = ref(window.history.state?.name || '');
+const personIntroduce = ref(window.history.state?.message || '');
+const personImage = ref(window.history.state?.image || '');
+
+// 监听history.state变化
+watch(
+  () => window.history.state,
+  (newState, oldState) => {
+    // 只有当id变化时才更新数据,避免不必要的刷新
+    if (newState?.id && newState.id !== oldState?.id) {
+      // 更新相关数据
+      personId.value = newState.id;
+      personName.value = newState.name;
+      personIntroduce.value = newState.message;
+      personImage.value = newState.image;
+    }
+  },
+  { immediate: true, deep: true }
+);
+</script>
+
+<style scoped lang="scss">
+@use "sass:math";
+// 定义rpx转换函数
+@function rpx($px) {
+  @return math.div($px, 750) * 100vw;
+}
+
+.home-container {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  flex-direction: row;
+  gap: rpx(0);
+  background: linear-gradient(to bottom, #e2ddfc, #f1effd);
+}
+
+.icon-expand {
+  width: rpx(8);
+  height: rpx(35);
+  border-top-right-radius: rpx(5);
+  border-bottom-right-radius: rpx(5);
+  z-index: 9999;
+  position: absolute;
+  top: 50%;
+  left: 18%;
+  transform: translateY(-50%);
+  background-color: #44449c;
+  cursor: pointer;
+  clip-path: polygon(0 0, 100% 15%, 100% 85%, 0 100%);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  transition: all 0.3s ease;
+}
+
+.icon-expand .vertical-lines {
+  color: #8a78d0;
+  font-size: rpx(10);
+}
+
+.content-wrapper {
+  display: flex;
+  flex: 1;
+}
+
+// 侧边栏
+.left-group2 {
+  // width: rpx(150);
+  height: 100%;
+  display: flex;
+  background-color: #ece9fd;
+}
+
+.title-box {
+  height: rpx(50);
+  position: absolute;
+}
+
+.box-icon {
+  width: 100%;
+  height: 100%;
+  flex: 1;
+  display: flex;
+  align-items: center;
+  color: black;
+  padding-left: rpx(15);
+  font-size: rpx(10);
+  cursor: pointer;
+}
+
+// .box-icon .left-icon {
+//   margin-left: rpx(5);
+//   margin-right: rpx(5);
+// }
+</style>

+ 158 - 0
src/views/AIPage/PlantExperts.vue

@@ -0,0 +1,158 @@
+<!-- 植物专家|图生视频 -->
+<template>
+  <!-- 植物专家 -->
+  <div class="home-container">
+     <!-- 展开收起侧边栏 -->
+    <div
+      class="icon-expand"
+      :style="{
+        backgroundColor: drawerVisible ? '#44449c' : '#7F70C840',
+        left: drawerVisible ? '18%' : '0'
+      }"
+      @click="toggleDrawer"
+    >
+      <span
+        class="vertical-lines"
+        :style="{
+          color: drawerVisible ? '#8a78d0' : 'white'
+        }"
+        >||</span
+      >
+    </div>
+
+    <!-- 左侧折叠面板 -->
+    <LeftPanel ref="leftPanelRef" v-if="drawerVisible"/>
+
+    <div class="left-group2">
+      <div class="title-box">
+        <div class="box-icon" @click="goBack">
+          <el-icon class="left-icon"><ArrowLeftBold /></el-icon>
+          返回首页|植物专家
+        </div>
+      </div>
+      <div class="img-box">
+        <p>
+          <img
+              style=" width: fit-content; height: 180px; margin: 10px;"
+              src="@/assets/images/farm.png"
+              class="avatar user"
+          />
+        </p>
+        <p>期待你的画作喔~</p>
+      </div>
+    </div>
+
+    <!-- 右侧图生视频组件 -->
+    <ImageToVideo />
+    
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { useRouter } from 'vue-router'
+import { ArrowLeftBold } from '@element-plus/icons-vue'
+import LeftPanel from '@/components/LeftPanel.vue'
+import ImageToVideo from '@/components/ai/video/ImageToVideo.vue'
+import {homeRoutes} from "@/router/index.js";
+
+const router = useRouter()
+const leftPanelRef = ref(null)
+const drawerVisible = ref(true)
+
+// 返回首页
+const goBack = () => {
+  router.push(homeRoutes.home);
+}
+
+// 添加切换抽屉显示状态的函数
+const toggleDrawer = () => {
+  drawerVisible.value = !drawerVisible.value
+}
+</script>
+
+<style scoped lang="scss">
+@use 'sass:math';
+// 定义rpx转换函数
+@function rpx($px) {
+  @return math.div($px, 750) * 100vw;
+}
+
+.home-container {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  display: flex;
+  flex-direction: row;
+  gap: rpx(0);
+  background: linear-gradient(
+    to bottom,
+    #e2ddfc,
+    #f1effd
+  );
+}
+
+.icon-expand {
+  width: rpx(8);
+  height: rpx(35);
+  border-top-right-radius: rpx(5);
+  border-bottom-right-radius: rpx(5);
+  z-index: 9999;
+  position: absolute;
+  top: 50%;
+  left: 18%;
+  transform: translateY(-50%);
+  background-color: #44449c;
+  cursor: pointer; 
+  clip-path: polygon(0 0, 100% 15%, 100% 85%, 0 100%);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  transition: all 0.3s ease;
+}
+
+.icon-expand .vertical-lines {
+  color: #8a78d0;
+  font-size: rpx(10);
+}
+
+.left-group2 {
+  width: rpx(150);
+  height: 100%;
+  background-color: #ece9fd;
+}
+
+.left-group2 img {
+  width: rpx(110);
+  height: auto;
+  margin-top: rpx(30);
+}
+
+.title-box {
+  height: rpx(50);
+}
+
+.box-icon {
+  width: 100%;
+  height: 100%;
+  flex: 1;
+  display: flex;
+  align-items: center;
+  color: black;
+  padding-left: rpx(15);
+  font-size: rpx(10);
+  cursor: pointer;
+}
+
+// .box-icon .left-icon {
+//   margin-left: rpx(10);
+//   margin-right: rpx(5);
+// }
+
+.img-box {
+  margin-top: rpx(50);
+  color: #a39dce;
+}
+</style>