Przeglądaj źródła

Merge remote-tracking branch 'origin/wanzi' into muzi

liyanbo 1 miesiąc temu
rodzic
commit
80cc26cd99
1 zmienionych plików z 282 dodań i 12 usunięć
  1. 282 12
      src/components/study/SelfDirectedLearning.vue

+ 282 - 12
src/components/study/SelfDirectedLearning.vue

@@ -13,6 +13,35 @@
             placeholder=""
             @keyup.enter.exact="doSendMessage(prompt.trim())"
           ></textarea>
+          <div class="dropdowns-container">
+            <el-dropdown 
+              v-for="dropdown in dropdowns" 
+              :key="dropdown.key"
+              v-model="dropdown.value"
+              @command="(command) => handleSelect(dropdown.key, command)"
+              @visible-change="(visible) => handleVisibleChange(dropdown.key, visible)"
+            >
+              <el-button type="primary">
+                <el-icon class="el-icon--left"><component :is="dropdown.icon" /></el-icon>
+                {{ dropdown.value }}
+                <el-icon class="el-icon--right" v-if="!dropdown.visible"><ArrowDownBold /></el-icon>
+                <el-icon class="el-icon--right" v-else><ArrowUpBold /></el-icon>
+              </el-button>
+              <template #dropdown>
+                <el-dropdown-menu class="dropdown-menu">
+                  <el-dropdown-item
+                    v-for="item in dropdown.options"
+                    :key="item.value"
+                    :command="item.value"
+                    >{{ item.label }}</el-dropdown-item
+                  >
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+          </div>
+          <button class="send-button" :class="{ 'active': prompt.trim().length > 0 }" @click="doSendMessage(prompt.trim())" :disabled="!prompt.trim().length">
+            <Top />
+          </button>
         </div>
       </div>
     </div>
@@ -21,10 +50,106 @@
 
 <script setup>
 import {ref} from "vue";
+import { Top, Search, User,Memo,ArrowUpBold,ArrowDownBold } from '@element-plus/icons-vue'
 
 // 发送消息输入框
 const prompt = ref(""); // prompt
 
+// 下拉框配置
+const dropdowns = ref([
+  {
+    key: 'course',
+    value: '诗词课',
+    visible: false,
+    icon: Search,
+    options: [
+      { label: '数学课', value: '数学课' },
+      { label: '英语课', value: '英语课' }
+    ]
+  },
+  {
+    key: 'teacher',
+    value: '主讲',
+    visible: false,
+    icon: User,
+    options: [
+      { label: '张老师', value: '张老师' },
+      { label: '李老师', value: '李老师' }
+    ]
+  },
+  {
+    key: 'assistant',
+    value: '助教',
+    visible: false,
+    icon: Memo,
+    options: [
+      { label: '小王', value: '小王' },
+      { label: '小李', value: '小李' },
+      { label: '小王', value: '小王' },
+      { label: '小李', value: '小李' },
+      { label: '小王', value: '小王' },
+      { label: '小李', value: '小李' },
+      { label: '小王', value: '小王' },
+      { label: '小李', value: '小李' },
+      { label: '小王', value: '小王' },
+      { label: '小李', value: '小李' }
+    ]
+  }
+]);
+
+// 下拉框配置映射,用于生成内容和正则表达式
+const dropdownConfig = {
+  course: {
+    prefix: '诗词课',
+    default: '诗词课',
+    regex: /诗词课[^,]+/g
+  },
+  teacher: {
+    prefix: '主讲为',
+    default: '主讲',
+    regex: /主讲为[^,]+/g
+  },
+  assistant: {
+    prefix: '助教为',
+    default: '助教',
+    regex: /助教为[^,]+/g
+  }
+};
+
+// 处理下拉框选择
+const handleSelect = (key, command) => {
+  const dropdown = dropdowns.value.find(item => item.key === key);
+  if (dropdown && dropdownConfig[key]) {
+    const config = dropdownConfig[key];
+    
+    // 生成新内容,仅当选择的值与默认值不同时添加
+    const newContent = command === config.default 
+      ? config.prefix 
+      : `${config.prefix}${command}`;
+    
+    // 检查输入框中是否已存在该类型的内容
+    if (config.regex.test(prompt.value)) {
+      // 替换已存在的内容
+      prompt.value = prompt.value.replace(config.regex, newContent);
+    } else {
+      // 添加到输入框,用逗号隔开
+      if (prompt.value.trim()) {
+        prompt.value += `, ${newContent}`;
+      } else {
+        prompt.value = newContent;
+      }
+    }
+  }
+};
+
+// 处理下拉框可见性变化
+const handleVisibleChange = (key, visible) => {
+  const dropdown = dropdowns.value.find(item => item.key === key);
+  if (dropdown) {
+    dropdown.visible = visible;
+  }
+};
+
 /** 处理来自 keydown 的发送消息 */
 const handleSendByKeydown = async (event) => {
   const content = prompt.value?.trim();
@@ -52,8 +177,6 @@ const doSendMessage = async (content) => {
   // 清空输入框
   prompt.value = "";
 
-  // 这里可以添加发送消息的逻辑
-  console.log("发送消息:", content);
 };
 </script>
 
@@ -76,7 +199,6 @@ const doSendMessage = async (content) => {
   display: flex;
   justify-content: center;
   align-items: center;
-  margin: rpx(0) 0;
 
   h3 {
     font-size: rpx(12);
@@ -87,8 +209,9 @@ const doSendMessage = async (content) => {
 
 .input-section {
   display: flex;
-  justify-content: center;
-  padding: rpx(10);
+  justify-content: flex-start;
+  margin-left: rpx(10);
+  width: calc(100% - rpx(10));
 }
 
 .dialogue-card {
@@ -105,7 +228,9 @@ const doSendMessage = async (content) => {
 }
 
 .user-input-card {
-  max-width: 80%;
+  width: 90%;
+  margin-left: rpx(20);
+  max-width: none;
   animation: dialogueEnterCenter 0.6s ease forwards;
 }
 
@@ -131,26 +256,109 @@ const doSendMessage = async (content) => {
   text-align: left;
   display: flex;
   flex-direction: column;
-  align-items: center;
-  justify-content: center;
+  position: relative;
   width: 100%;
 }
 
 .user-input-textarea {
-  width: 95%;
-  min-height: rpx(50);
+  width: 100%;
+  min-height: rpx(70);
   max-height: rpx(150);
   border: none;
   outline: none;
   background: transparent;
-  font-size: rpx(10);
+  font-size: rpx(8);
   line-height: 1.2;
   color: #333;
   resize: none;
   font-family: inherit;
   overflow-y: auto;
   text-align: left;
-  padding: rpx(5) 0;
+  padding: rpx(5) rpx(0);
+}
+
+.dropdowns-container {
+  display: flex;
+  gap: rpx(5);
+  margin-top: rpx(5);
+  align-self: flex-start;
+}
+
+.dropdowns-container .el-button {
+  width: rpx(50);
+  height: rpx(18);
+  background-color: #f1f0ff;
+  border: rpx(1) solid #a7a4ed;
+  color: black;
+  border-radius: rpx(4);
+  font-size: rpx(8);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+
+.dropdown-menu {
+  min-width: rpx(50);
+  width: auto;
+  max-height: rpx(160);
+  overflow-y: auto;
+  border-radius: rpx(3);
+  border: 1px white solid;
+  background-color: rgb(255, 255, 255, 0.5);
+  backdrop-filter: blur(rpx(5));
+  box-shadow: 0 4px 8px rgba(202, 52, 52, 0.1);
+}
+
+.dropdown-menu ::v-deep::-webkit-scrollbar {
+  width: rpx(2);
+}
+
+.dropdown-menu ::v-deep::-webkit-scrollbar-track {
+  background: #f1f1f1;
+  border-radius: rpx(2);
+}
+
+.dropdown-menu ::v-deep::-webkit-scrollbar-thumb {
+  background: #c1c1c1;
+  border-radius: rpx(2);
+}
+
+.dropdown-menu ::v-deep::-webkit-scrollbar-thumb:hover {
+  background: #a8a8a8;
+}
+
+.dropdown-menu ::v-deep(.el-dropdown-menu__item) {
+  font-size: rpx(8);
+  color: black;
+  border-radius: rpx(5);
+  width: auto;
+  min-width: rpx(35);
+  height: rpx(20);
+  margin-bottom: rpx(8);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0 rpx(8);
+}
+
+.dropdown-menu ::v-deep(.el-dropdown-menu__item:hover),
+.dropdown-menu ::v-deep(.el-dropdown-menu__item:focus),
+.dropdown-menu ::v-deep(.el-dropdown-menu__item:active) {
+  background: linear-gradient(
+    to bottom,
+    #fee78a,
+    #ffce1b
+  );
+  border: none;
+  outline: none;
+}
+
+/* 确保下拉按钮点击时也没有边框 */
+.dropdowns-container .el-button:focus,
+.dropdowns-container .el-button:active {
+  outline: none;
+  box-shadow: none;
 }
 
 /* 滚动条样式 */
@@ -172,5 +380,67 @@ const doSendMessage = async (content) => {
   background: rgba(64, 158, 255, 0.8);
 }
 
+.send-button {
+  position: absolute;
+  bottom: rpx(0);
+  right: rpx(0);
+  width: rpx(20);
+  height: rpx(20);
+  border-radius: 50%;
+  background: transparent;
+  color: #a7a4ed;
+  border: rpx(1) solid #a7a4ed;
+  font-size: rpx(3);
+  font-weight: bold;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  cursor: not-allowed;
+  transition: all 0.3s ease;
+  outline: none;
+  box-shadow: none;
+  opacity: 0.6;
+}
+
+.send-button.active {
+  background: linear-gradient(
+    to bottom,
+    #ffefb0,
+    #ffcc00
+  );
+  color: white;
+  border: none;
+  cursor: pointer;
+  opacity: 1;
+}
+
+.send-button:hover:not(.active) {
+  border-color: #a7a4ed;
+  color: #a7a4ed;
+  transform: none;
+  outline: none;
+  box-shadow: none;
+}
+
+.send-button:hover.active {
+  transform: scale(1.1);
+  outline: none;
+  box-shadow: 0 rpx(2) rpx(5) rgba(255, 204, 0, 0.3);
+}
+
+.send-button:active.active {
+  transform: scale(0.95);
+  outline: none;
+  box-shadow: none;
+}
+
+.send-button:focus {
+  outline: none;
+  box-shadow: none;
+}
+
+.send-button span {
+  display: block;
+}
 
 </style>