copilot助手完成
This commit is contained in:
		| @@ -2,12 +2,17 @@ | ||||
|  | ||||
| export default { | ||||
|   name: "AppCopilot", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <section class="AppCopilot"> | ||||
|     <ai-copilot/> | ||||
|     <ai-copilot :http="instance"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
|   | ||||
| @@ -5,26 +5,27 @@ import ThinkingBar from "./components/thinkingBar.vue"; | ||||
| export default { | ||||
|   name: "AiCopilot", | ||||
|   props: { | ||||
|     http: Function, | ||||
|     title: {default: "Copilot小助理"} | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       show: false, | ||||
|       expand: false, | ||||
|       loading: true, | ||||
|       loading: false, | ||||
|       prompt: "", | ||||
|       history: [ | ||||
|         {avatar: "https://cdn.sinoecare.com/i/2024/06/04/665ec6f5ef213.png", msg: "你好", uid: "ai"}, | ||||
|         { | ||||
|           avatar: "", | ||||
|           msg: "AI 聊天机器人 ChatGPT 近日突然出现闪崩,响应超时或无法正常工作,故障长达近 7 小时。全球大量用户处于焦虑等待,因为许多人对此已经产生了依赖,工作不能自理。一些备选工具如 Perplexity、Claude 等也遭遇故障。摩根士丹利的数据显示,ChatGPT 故障后,谷歌 AI 聊天机器人 Gemini 搜索量激增 60%,达 327058 次,显示出用户把它视为 ChatGPT 的直接替代选项\n" + | ||||
|               "\n" + | ||||
|               "作者:RTE开发者社区\n" + | ||||
|               "链接:https://juejin.cn/post/7377025870630862874\n" + | ||||
|               "来源:稀土掘金\n" + | ||||
|               "著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。", | ||||
|           uid: "me" | ||||
|         }, | ||||
|         // {avatar: "https://cdn.sinoecare.com/i/2024/06/04/665ec6f5ef213.png", msg: "你好", uid: "ai"}, | ||||
|         // { | ||||
|         //   avatar: "", | ||||
|         //   msg: "AI 聊天机器人 ChatGPT 近日突然出现闪崩,响应超时或无法正常工作,故障长达近 7 小时。全球大量用户处于焦虑等待,因为许多人对此已经产生了依赖,工作不能自理。一些备选工具如 Perplexity、Claude 等也遭遇故障。摩根士丹利的数据显示,ChatGPT 故障后,谷歌 AI 聊天机器人 Gemini 搜索量激增 60%,达 327058 次,显示出用户把它视为 ChatGPT 的直接替代选项\n" + | ||||
|         //       "\n" + | ||||
|         //       "作者:RTE开发者社区\n" + | ||||
|         //       "链接:https://juejin.cn/post/7377025870630862874\n" + | ||||
|         //       "来源:稀土掘金\n" + | ||||
|         //       "著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。", | ||||
|         //   uid: "me" | ||||
|         // }, | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
| @@ -33,9 +34,43 @@ export default { | ||||
|   }, | ||||
|   components: {ThinkingBar, ChatContent}, | ||||
|   methods: { | ||||
|     getHistory(cb) { | ||||
|       this.http.post("/app/appaicopilotinfo/list").then(res => { | ||||
|         if (res?.data) { | ||||
|           if (cb) cb(res.data.records) | ||||
|           else this.history = res.data.records | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleHotkey(evt) { | ||||
|       if (evt.ctrlKey && evt.key == "Enter") { | ||||
|         this.handleSend() | ||||
|       } | ||||
|     }, | ||||
|     handleSend() { | ||||
|  | ||||
|       const concatenateStr = (content, i = 0) => { | ||||
|         this.history.at(-1).content += content.slice(i, i + 1) | ||||
|         if (++i < content.length) setTimeout(() => concatenateStr(content, i), 50) | ||||
|       } | ||||
|       this.$debounce(() => { | ||||
|         const message = {appType: "2", userType: 0, content: this.prompt} | ||||
|         this.history.push(message) | ||||
|         this.loading = true | ||||
|         this.prompt = "" | ||||
|         this.http.post("/app/appaicopilotinfo/add", message).then(res => { | ||||
|           if (res?.data?.length >= 2) { | ||||
|             const last = res.data.at(-1) | ||||
|             this.history.push({...last, content: ""}) | ||||
|             concatenateStr(last.content) | ||||
|           } | ||||
|         }).finally(() => { | ||||
|           this.loading = false | ||||
|         }) | ||||
|       }, 100) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getHistory() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| @@ -55,7 +90,7 @@ export default { | ||||
|           <chat-content class="fill" :list="history"/> | ||||
|           <div class="sendBox flex gap-14"> | ||||
|             <el-input type="textarea" class="fill input" autosize resize="none" v-model="prompt" placeholder="请输入..." | ||||
|                       @change="handleSend"/> | ||||
|                       @keydown.native="handleHotkey" :disabled="loading" :placeholder="loading?'正在思考中...':'请输入'"/> | ||||
|             <div class="sendBtn" @click="handleSend"/> | ||||
|           </div> | ||||
|         </div> | ||||
| @@ -134,7 +169,7 @@ export default { | ||||
|       .right { | ||||
|         width: 420px; | ||||
|         height: 100%; | ||||
|         padding: 14px; | ||||
|         padding: 14px 0 14px 14px; | ||||
|         align-items: stretch; | ||||
|         border-left: 1px solid transparent; | ||||
|  | ||||
| @@ -154,6 +189,7 @@ export default { | ||||
|  | ||||
|       :deep(.sendBox) { | ||||
|         width: 100%; | ||||
|         padding-right: 14px; | ||||
|  | ||||
|         .input > textarea { | ||||
|           width: 100%; | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| <template> | ||||
|   <section class="chatContent"> | ||||
|   <el-scrollbar class="chatContent"> | ||||
|     <div class="chat-wrapper" v-for="item in list" :key="item.id"> | ||||
|       <div class="chat-text" :class="{right:item.uid == 'me'}"> | ||||
|         <img class="avatar" :src="item.avatar" alt=""/> | ||||
|         <div class="content" v-text="item.msg"/> | ||||
|       <div class="chat-text" :class="{right:item.userType == '0'}"> | ||||
|         <img class="avatar" :src="avatar(item)" alt=""/> | ||||
|         <div class="content" v-text="item.content"/> | ||||
|       </div> | ||||
|     </div> | ||||
|   </section> | ||||
|   </el-scrollbar> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| @@ -16,38 +16,36 @@ export default { | ||||
|   props: { | ||||
|     list: {default: () => []} | ||||
|   }, | ||||
|   computed: { | ||||
|     lastMessage: v => v.list.at(-1)?.content | ||||
|   }, | ||||
|   watch: { | ||||
|     list: { | ||||
|       deep: true, handler() { | ||||
|         this.scrollBottom() | ||||
|       } | ||||
|     lastMessage() { | ||||
|       this.scrollBottom() | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     scrollBottom() { | ||||
|       this.$el.scrollTop = this.$el.scrollHeight - this.$el.clientHeight | ||||
|       const content = this.$el.querySelector(".el-scrollbar__wrap") | ||||
|       if (content) { | ||||
|         content.scrollTop = content.scrollHeight - content.clientHeight | ||||
|       } | ||||
|     }, | ||||
|     optimizeMessage(msg = "") { | ||||
|       return msg.trim() | ||||
|     avatar(item) { | ||||
|       return item.avatar || (item.userType == '0' ? 'https://cdn.sinoecare.com/i/2024/06/17/666fdb275be82.png' : | ||||
|           'https://cdn.sinoecare.com/i/2024/06/04/665ec6f5ef213.png') | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.scrollBottom() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .chatContent { | ||||
|   overflow-y: auto; | ||||
|  | ||||
|   &::-webkit-scrollbar { | ||||
|     width: 3px; | ||||
|     /* 设置滚动条宽度 */ | ||||
|   } | ||||
|  | ||||
|   &::-webkit-scrollbar-thumb { | ||||
|     background-color: rgb(66, 70, 86); | ||||
|     /* 设置滚动条滑块的背景色 */ | ||||
|     border-radius: 50%; | ||||
|     /* 设置滑块的圆角 */ | ||||
|   :deep(.el-scrollbar__wrap) { | ||||
|     overflow-x: hidden; | ||||
|   } | ||||
|  | ||||
|   .chat-text { | ||||
| @@ -55,6 +53,8 @@ export default { | ||||
|     gap: 12px; | ||||
|     font-size: 14px; | ||||
|     color: #333333; | ||||
|     margin-bottom: 8px; | ||||
|     padding-right: 14px; | ||||
|  | ||||
|     .content { | ||||
|       position: relative; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user