浏览代码

代码优化

chd 5 月之前
父节点
当前提交
feede377c6

+ 70 - 395
src/entrypoints/sidepanel/Chat.vue

@@ -16,7 +16,13 @@
                 <span class="dot"></span>
               </span>
             </div>
-            <div v-else class="content">{{ message.content }}</div>
+            <div v-else class="content">{{ message.content }}
+              <span class="loading-indicator" v-if="sendLoading && index === messages.length - 1">
+                <span class="dot"></span>
+                <span class="dot"></span>
+                <span class="dot"></span>
+              </span>
+            </div>
             <div class="timestamp ">{{ message.timestamp }}
               <span v-if="message.add" style="cursor: pointer;" @click="handleInput">填充</span>
             </div>
@@ -48,7 +54,7 @@
           </div>
           <div class="card-btn">
             <el-tooltip content="总结当前页面" placement="top">
-              <el-button round @click="handleCardButtonClick" :disabled="!taklToHtml">总结</el-button>
+              <el-button round @click="handleSummary" :disabled="!taklToHtml">总结</el-button>
             </el-tooltip>
 
             <el-tooltip content="选择后,在输入框描述填表流程" placement="top">
@@ -80,15 +86,15 @@
 import {ref, onMounted, nextTick, inject, useTemplateRef} from 'vue'
 import {ElScrollbar, ElAvatar, ElInput, ElButton} from 'element-plus'
 import moment from "moment";
-import { buildExcelUnderstandingPrompt ,getFileSummaryPrompt} from '@/utils/ai-service.js'
+import { buildExcelUnderstandingPrompt ,getFileSummaryPrompt,getSummaryPrompt,getFileContent,buildObjPrompt } from '@/utils/ai-service.js'
 import * as XLSX from "xlsx";
 import {ElMessage} from 'element-plus';
 import {useMsg} from '@/entrypoints/sidepanel/hook/useMsg.ts';
 import Tools from "@/entrypoints/sidepanel/component/tools.vue";
 import historyComponent from '@/entrypoints/sidepanel/component/historyComponent.vue';
-import {useSummary} from '@/entrypoints/sidepanel/hook/useSummary.ts'
 import {mockData, startMsg, mockData2} from "@/entrypoints/sidepanel/mock"
-import {useAutoResizeTextarea} from '@/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts';
+import { useAutoResizeTextarea } from '@/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts';
+import {getPageInfo} from './utils/index.js'
 
 // 滚动条引用
 const scrollbar = ref(null);
@@ -101,21 +107,41 @@ const {registerStore, useStore} = inject('indexedDBHook');
 const {
   msgUuid,
   messages,
-  inputMessage,
-  indexTemp,
   taklToHtml,
-  pageInfo,
   sendLoading,
-  type,
-  addMessage,
-  sendRequese,
-  getPageInfo,
   streamRes,
   handleInput,
-  getFileValue
-} = useMsg(scrollbar, xlsxData, fetchDataAndProcess);
-const {handleCardButtonClick} = useSummary(addMessage, sendRequese);
+  getFormKeyAndValue
+} = useMsg(scrollbar, xlsxData);
+const inputMessage = ref('')
+const pageInfo = ref('')
+const addMessage = (msg, raw) => {
+        if (!msg) return
+        const newMessage = reactive({
+            id: messages.value.length + 1,
+            username: '我',
+            rawContent:raw ?? msg,
+            content: msg,
+            timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+            isSelf: true,
+            avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
+            addToHistory: !taklToHtml.value
+        })
+        messages.value.push(newMessage)
+        useStore(msgUuid.value).add(newMessage)
+        // 滚动到底部
+        nextTick(() => {
+            scrollbar.value?.setScrollTop(99999);
+        })
+        return newMessage
 
+    }
+const handleSummary = async () => {
+  const res = await getPageInfo()
+  addMessage('总结页面',getSummaryPrompt(res.content))
+  streamRes()
+}
+const type = ref('')
 function handelIntelligentFillingClick() {
   inputMessage.value = '/智能填表 '
   type.value = '2'
@@ -156,8 +182,9 @@ function addNewDialogue() {
 
 async function handleAsk() {
   if (sendLoading.value) return;
-  addMessage(inputMessage.value.trim(), true);
+  addMessage(inputMessage.value.trim());
   inputMessage.value = '';
+  streamRes(taklToHtml)
 }
 
 function handleCapture() {
@@ -177,9 +204,6 @@ const titleScroll = computed(() => {
   return pageInfo.value?.title?.length > 20 // 当标题超过20个字符时触发滚动
 })
 
-// let formMap = []
-let formInfo = []
-const flag = ref(false)  //true调用算法接口
 
 const handleUpload =async (file) => {
   if (type.value === '2') {
@@ -189,13 +213,12 @@ const handleUpload =async (file) => {
     if (chrome.runtime.lastError) {
       console.error("消息发送错误:", chrome.runtime.lastError);
     } else {
-      addMessage(`已上传文件:${file.name}`, false)
       const fileExtension = file.name.split('.').pop().toLowerCase();
       if (response.status === 'error') return ElMessage({message:response.message,type: 'error', duration: 4 * 1000, grouping: true})
       formInfo = response.data
       if (fileExtension === 'xlsx') {
         const reader = new FileReader();
-        reader.readAsArrayBuffer(file);
+        reader.readAsArrayBuffer(file)  
         reader.onload = async (e) => {
           const data = new Uint8Array(e.target.result);
           const workbook = XLSX.read(data, {
@@ -222,105 +245,41 @@ const handleUpload =async (file) => {
             // if (!xlsxData.value[header]) xlsxData.value[header] = []
             xlsxData.value[header] = readData[1][i]
           })
-          if (type.value === '2') {
-            await streamRes(buildExcelUnderstandingPrompt(readData, file?.name, response.data), false)
-          }
+          addMessage(`已上传文件:${file.name}`,buildExcelUnderstandingPrompt(readData, file?.name, response.data))
+          await streamRes()
         };
       } else {
-        await getFileValue(file, response.data)
-
-        // const keys = Object.keys(res)
-        // const values = Object.values(res)
-        // readData[0].forEach((header, i) => {
-        //   if (!xlsxData.value[header]) xlsxData.value[header] = []
-        //   xlsxData.value[header].push(readData[1][i])
-        // })
-        // console.log(res);
-      }
-
-    }
+          const msg = addMessage(`文件上传中`,)
+          sendLoading.value = true
+           let formData = new FormData();
+          formData.append("file", file);
+          const res = await getFileContent(formData)
+          sendLoading.value = false
+          msg.content = `已上传文件:${file.name}`
+          msg.rawContent = getFileSummaryPrompt(res.data, file.name)
+          const res2 = await getFormKeyAndValue(res.data,response.data)
+             xlsxData.value = res2.data
+                console.log(xlsxData.value);
+                console.log(type.value);
+         }
+       }
     return true
   });
-
   }
   if (type.value === '') {
-    addMessage(`已上传文件:${file.name}`, false)
-    await getFileValue(file, )
-
+    const msg = addMessage(`文件上传中`,)
+    sendLoading.value = true
+     let formData = new FormData();
+    formData.append("file", file);
+    const res = await getFileContent(formData)
+    sendLoading.value = false
+    msg.content = `已上传文件:${file.name}`
+    msg.rawContent = getFileSummaryPrompt(res.data, file.name)
+    streamRes()
   }
 }
 let str = ''
-async function fetchDataAndProcess(input, obj) {
-  if (input.startsWith('/智能填表')) {
-    input = input.split('/智能填表')[1]
-  }
-  str = input
-  console.log(str);
-  const pageInfo = await getPageInfo();
-  await new Promise(res => setTimeout(() => {
-    res()
-  }, 2000))
-  // const res = await hepl({
-  //   input_data: input,
-  //   body: pageInfo.content.mainContent
-  // })
-  console.log(pageInfo.title);
 
-  const res = await new Promise((resolve, reject) => {
-    setTimeout(() => {
-      resolve({ data:pageInfo.title === '智能招采' ?  mockData[indexTemp.value] :mockData2[indexTemp.value] })
-    }, 1000)
-  })
-  if (!res.data.tag || res.data.tag === 'undefined') {
-    ElMessage({ message: '未找到标签,请重试', type: 'error', duration: 4 * 1000, grouping: true })
-    obj.content = '未找到标签,请重试'
-    type.value = ''
-    return
-  }
-  await handleClick(res.data, obj);
-}
-
-
-async function handleClick(res, msgObj) {
-  await new Promise(resolve => setTimeout(resolve, 2000))
-  msgObj.content = `点击${res.tag}元素`
-  chrome.runtime.sendMessage({
-    type: 'FROM_SIDE_PANEL_TO_ACTION',
-    data: res
-  }, async ({ data, status }) => {
-    if (chrome.runtime.lastError) {
-      console.error("消息发送错误:", chrome.runtime.lastError);
-      rej(chrome.runtime.lastError)
-    } else {
-      if (status === 'error') {
-        msgObj.content = data
-        type.value = ''
-        return
-      }
-      if (res.next === '是') {
-        const arr = str.split(',')
-        arr.shift()
-        str = arr.join(',')
-        indexTemp.value++
-        fetchDataAndProcess(str, msgObj)
-      } else {
-        if (type.value === '2') {
-           await new Promise((resolve, reject) => {
-    setTimeout(() => {
-      resolve()
-    }, 2000)
-  })
-          msgObj.content = `请上传数据`
-          ElMessage({ message: '请上传数据', type: 'success', duration: 4 * 1000, grouping: true })
-        } else {
-          msgObj.content = `执行完毕`
-        }
-      }
-    }
-    return true
-  });
-
-}
 
 const isHoveringTitle = ref(false)
 
@@ -330,15 +289,12 @@ onMounted(() => {
   chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
     if (message.type === 'TO_SIDE_PANEL_PAGE_INFO') {
       pageInfo.value = message.data
-      console.log(pageInfo.value);
-
       // 转发到 content.js
       chrome.tabs.sendMessage(sender.tab.id, {
         type: 'TO_CONTENT_SCRIPT',
         data: message.data
       });
     }
-
     if (message.type === 'TO_SIDE_PANEL_PAGE_CHANGE') {
       pageInfo.value = message.data
     }
@@ -374,286 +330,5 @@ onMounted(() => {
 </script>
 
 <style lang="scss" scoped>
-.chat-container {
-  height: 100vh;
-  display: flex;
-  flex-direction: column;
-  border: 1px solid #dcdfe6;
-  border-radius: 4px;
-  background-color: #F0F0F0;
-  font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
-}
-
-.message-list {
-  flex: 1;
-  padding: 16px;
-  overflow: auto;
-}
-
-.messages {
-  min-height: 100%;
-  display: flex;
-  flex-direction: column;
-}
-
-.message-item {
-  display: flex;
-  margin-bottom: 20px;
-  gap: 12px;
-  color: #333;
-  align-items: flex-start;
-  animation: fadeIn 0.3s ease-in-out;
-}
-
-@keyframes fadeIn {
-  from {
-    opacity: 0;
-    transform: translateY(10px);
-  }
-
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
-}
-
-.message-item.self {
-  flex-direction: row-reverse;
-}
-
-.message-content {
-  max-width: 80%;
-}
-
-.username {
-  font-size: 14px;
-  color: #606266;
-  margin-bottom: 4px;
-}
-
-.content {
-  padding: 12px;
-  min-height: 40px;
-  background-color: #F0F4F8;
-  border-radius: 12px;
-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
-  word-break: break-all;
-  line-height: 1.5;
-  font-size: 14px;
-}
-
-.content :deep(pre) {
-  margin: 10px 0;
-  border-radius: 8px;
-}
-
-.content :deep(code) {
-  font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
-}
-
-.content :deep(p) {
-  margin: 8px 0;
-}
-
-.content :deep(ul),
-.content :deep(ol) {
-  padding-left: 20px;
-  margin: 8px 0;
-}
-
-.content :deep(blockquote) {
-  border-left: 4px solid #ddd;
-  padding-left: 10px;
-  color: #666;
-  margin: 8px 0;
-}
-
-.self .content {
-  background: #409eff;
-  color: white;
-  border-bottom-right-radius: 4px;
-}
-
-.other .content {
-  border-bottom-left-radius: 4px;
-}
-
-.timestamp {
-  display: flex;
-  justify-content: space-between;
-  font-size: 12px;
-  color: #909399;
-  margin-top: 6px;
-}
-
-.timestamp span {
-  transition: color 0.2s;
-}
-
-.timestamp span:hover {
-  color: #409eff;
-}
-
-.info-card {
-  margin: 10px;
-}
-
-/* .card-content:hover {
-  transform: translateY(-2px);
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
-} */
-
-.card-icon {
-  color: #409eff;
-}
-
-.title-wrapper {
-  flex: 1;
-  overflow: hidden;
-  position: relative;
-}
-
-.title-scroller {
-  display: inline-block;
-  white-space: nowrap;
-  color: #333;
-  font-weight: 500;
-}
-
-.title-scroller.scroll {
-  animation: scrollTitle 10s linear infinite;
-}
-
-@keyframes scrollTitle {
-  0% {
-    transform: translateX(0);
-  }
-
-  100% {
-    transform: translateX(-100%);
-  }
-}
-
-.upload :deep(.el-icon) {
-  transition: color 0.3s;
-}
-
-.can-hover :deep(.el-icon:hover) {
-  color: #409eff !important;
-}
-
-.el-check-tag {
-  margin-right: 8px;
-  transition: all 0.3s;
-}
-
-.el-check-tag:hover {
-  transform: scale(1.05);
-}
-
-/* 加载中的消息样式 */
-.loading-content {
-  min-height: 40px;
-  display: flex;
-  align-items: center;
-  justify-content: flex-start;
-}
-
-.loading-indicator {
-  display: inline-block;
-  align-items: center;
-  gap: 4px;
-  margin-left: 2px;
-
-  .dot {
-    width: 4px;
-    height: 4px;
-    margin: 0 2px;
-    background-color: gray;
-    border-radius: 50%;
-    display: inline-block;
-    animation: pulse 1.5s infinite ease-in-out;
-  }
-
-  .dot:nth-child(2) {
-    animation-delay: 0.3s;
-  }
-
-  .dot:nth-child(3) {
-    animation-delay: 0.6s;
-  }
-
-  @keyframes pulse {
-
-    0%,
-    100% {
-      transform: scale(0.8);
-      opacity: 0.6;
-    }
-
-    50% {
-      transform: scale(1.2);
-      opacity: 1;
-    }
-  }
-}
-
-
-.input-area {
-  padding: 8px 10px;
-  color: black;
-  background-color: #fff;
-  border: 1px solid rgba(102, 102, 102, 0.3);
-  border-radius: 16px;
-  margin: 0 12px 12px;
-
-  .card-content {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-    padding: 14px 12px;
-    margin: 0 0 6px;
-    background: #fff;
-    border-radius: 10px;
-    border: 1px solid rgba(0, 0, 0, 0.08);
-    font-size: 14px;
-    /* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);*/
-    transition: transform 0.4s;
-  }
-
-  .card-btn {
-    padding: 0 0 4px;
-
-    .op {
-      margin-right: 3px;
-    }
-  }
-
-  .chat_area_op {
-    margin-top: 3px;
-    display: flex;
-    justify-content: end;
-  }
-}
-
-.input-area:hover {
-  border-color: rgba(102, 102, 102, 0.4);
-}
-
-.input-area :deep(.el-textarea__inner) {
-  border-radius: 8px;
-  transition: border-color 0.3s;
-  resize: none;
-  box-shadow: none;
-}
-
-.input-area :deep(.el-textarea__inner) {
-  padding: 0 4px;
-  margin-top: 3px;
-}
-
-.input-area :deep(.el-textarea__inner:focus) {
-  border-color: #409eff;
-  box-shadow: none;
-}
+@import '@/entrypoints/sidepanel/css/chat.scss';
 </style>

+ 69 - 0
src/entrypoints/sidepanel/component/inputArea.vue

@@ -0,0 +1,69 @@
+<script setup>
+import { ref } from "vue";
+import { options } from "@/entrypoints/sidepanel/mock";
+import { Reading, Upload, Paperclip, Scissor, AlarmClock, CirclePlus } from "@element-plus/icons-vue";
+
+const isShowPage = ref(false)
+const taklToHtml = ref(false)
+
+const inputMessage = ref('')
+
+const emit = defineEmits(['readClick', 'uploadFile', 'handleCapture', 'addNewDialogue', 'hisRecords'])
+</script>
+
+<template>
+    <div class="input-area">
+        <div v-show="isShowPage" style="border-bottom: 1px solid #F0F0F0;">
+          <div class="card-content">
+            <img :src="pageInfo?.favIconUrl" style="width: 24px;" />
+            <div class="title-wrapper">
+              <div class="title-scroller" :class="{ 'scroll': isHoveringTitle && titleScroll }">
+                {{ pageInfo?.title }}
+              </div>
+            </div>
+            <el-icon size="16px" @click="isShowPage = false; taklToHtml = false">
+              <CircleClose />
+            </el-icon>
+          </div>
+          <div class="card-btn">
+            <el-tooltip content="总结当前页面" placement="top">
+              <el-button round @click="handleCardButtonClick" :disabled="!taklToHtml">总结</el-button>
+            </el-tooltip>
+
+            <el-tooltip content="选择后,在输入框描述填表流程" placement="top">
+              <el-button round @click="handelIntelligentFillingClick" :disabled="!taklToHtml">智能填表</el-button>
+            </el-tooltip>
+          </div>
+        </div>
+
+        <el-input ref="textareaRef" v-model="inputMessage" type="textarea" :rows="3" placeholder="输入消息..."
+                  @keyup.enter="handleAsk"/>
+        <div class="chat_area_op">
+          <el-button type="primary" link @click="handleAsk" :disabled="!inputMessage.trim() || sendLoading">
+            <el-icon size="18" :color="inputMessage.trim() ? 'black' : 'gray'">
+              <Promotion/>
+            </el-icon>
+          </el-button>
+        </div>
+      </div>
+
+</template>
+
+<style lang="scss" scoped>
+.input-area :deep(.el-textarea__inner) {
+  border-radius: 8px;
+  transition: border-color 0.3s;
+  resize: none;
+  box-shadow: none;
+}
+
+.input-area :deep(.el-textarea__inner) {
+  padding: 0 4px;
+  margin-top: 3px;
+}
+
+.input-area :deep(.el-textarea__inner:focus) {
+  border-color: #409eff;
+  box-shadow: none;
+}
+</style>

+ 282 - 0
src/entrypoints/sidepanel/css/chat.scss

@@ -0,0 +1,282 @@
+.chat-container {
+    height: 100vh;
+    display: flex;
+    flex-direction: column;
+    border: 1px solid #dcdfe6;
+    border-radius: 4px;
+    background-color: #F0F0F0;
+    font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
+}
+
+.message-list {
+    flex: 1;
+    padding: 16px;
+    overflow: auto;
+}
+
+.messages {
+    min-height: 100%;
+    display: flex;
+    flex-direction: column;
+}
+
+.message-item {
+    display: flex;
+    margin-bottom: 20px;
+    gap: 12px;
+    color: #333;
+    align-items: flex-start;
+    animation: fadeIn 0.3s ease-in-out;
+}
+
+@keyframes fadeIn {
+    from {
+        opacity: 0;
+        transform: translateY(10px);
+    }
+
+    to {
+        opacity: 1;
+        transform: translateY(0);
+    }
+}
+
+.message-item.self {
+    flex-direction: row-reverse;
+}
+
+.message-content {
+    max-width: 80%;
+}
+
+.username {
+    font-size: 14px;
+    color: #606266;
+    margin-bottom: 4px;
+}
+
+.content {
+    padding: 12px;
+    min-height: 40px;
+    background-color: #F0F4F8;
+    border-radius: 12px;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+    word-break: break-all;
+    line-height: 1.5;
+    font-size: 14px;
+}
+
+.content :deep(pre) {
+    margin: 10px 0;
+    border-radius: 8px;
+}
+
+.content :deep(code) {
+    font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
+}
+
+.content :deep(p) {
+    margin: 8px 0;
+}
+
+.content :deep(ul),
+.content :deep(ol) {
+    padding-left: 20px;
+    margin: 8px 0;
+}
+
+.content :deep(blockquote) {
+    border-left: 4px solid #ddd;
+    padding-left: 10px;
+    color: #666;
+    margin: 8px 0;
+}
+
+.self .content {
+    background: #409eff;
+    color: white;
+    border-bottom-right-radius: 4px;
+}
+
+.other .content {
+    border-bottom-left-radius: 4px;
+}
+
+.timestamp {
+    display: flex;
+    justify-content: space-between;
+    font-size: 12px;
+    color: #909399;
+    margin-top: 6px;
+}
+
+.timestamp span {
+    transition: color 0.2s;
+}
+
+.timestamp span:hover {
+    color: #409eff;
+}
+
+.info-card {
+    margin: 10px;
+}
+
+/* .card-content:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
+} */
+
+.card-icon {
+    color: #409eff;
+}
+
+.title-wrapper {
+    flex: 1;
+    overflow: hidden;
+    position: relative;
+}
+
+.title-scroller {
+    display: inline-block;
+    white-space: nowrap;
+    color: #333;
+    font-weight: 500;
+}
+
+.title-scroller.scroll {
+    animation: scrollTitle 10s linear infinite;
+}
+
+@keyframes scrollTitle {
+    0% {
+        transform: translateX(0);
+    }
+
+    100% {
+        transform: translateX(-100%);
+    }
+}
+
+.upload :deep(.el-icon) {
+    transition: color 0.3s;
+}
+
+.can-hover :deep(.el-icon:hover) {
+    color: #409eff !important;
+}
+
+.el-check-tag {
+    margin-right: 8px;
+    transition: all 0.3s;
+}
+
+.el-check-tag:hover {
+    transform: scale(1.05);
+}
+
+/* 加载中的消息样式 */
+.loading-content {
+    min-height: 40px;
+    display: flex;
+    align-items: center;
+    justify-content: flex-start;
+}
+
+.loading-indicator {
+    display: inline-block;
+    align-items: center;
+    gap: 4px;
+    margin-left: 2px;
+
+    .dot {
+        width: 4px;
+        height: 4px;
+        margin: 0 2px;
+        background-color: gray;
+        border-radius: 50%;
+        display: inline-block;
+        animation: pulse 1.5s infinite ease-in-out;
+    }
+
+    .dot:nth-child(2) {
+        animation-delay: 0.3s;
+    }
+
+    .dot:nth-child(3) {
+        animation-delay: 0.6s;
+    }
+
+    @keyframes pulse {
+
+        0%,
+        100% {
+            transform: scale(0.8);
+            opacity: 0.6;
+        }
+
+        50% {
+            transform: scale(1.2);
+            opacity: 1;
+        }
+    }
+}
+
+
+.input-area {
+    padding: 8px 10px;
+    color: black;
+    background-color: #fff;
+    border: 1px solid rgba(102, 102, 102, 0.3);
+    border-radius: 16px;
+    margin: 0 12px 12px;
+
+    .card-content {
+        display: flex;
+        align-items: center;
+        gap: 12px;
+        padding: 14px 12px;
+        margin: 0 0 6px;
+        background: #fff;
+        border-radius: 10px;
+        border: 1px solid rgba(0, 0, 0, 0.08);
+        font-size: 14px;
+        /* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);*/
+        transition: transform 0.4s;
+    }
+
+    .card-btn {
+        padding: 0 0 4px;
+
+        .op {
+            margin-right: 3px;
+        }
+    }
+
+    .chat_area_op {
+        margin-top: 3px;
+        display: flex;
+        justify-content: end;
+    }
+}
+
+.input-area:hover {
+    border-color: rgba(102, 102, 102, 0.4);
+}
+
+.input-area :deep(.el-textarea__inner) {
+    border-radius: 8px;
+    transition: border-color 0.3s;
+    resize: none;
+    box-shadow: none;
+}
+
+.input-area :deep(.el-textarea__inner) {
+    padding: 0 4px;
+    margin-top: 3px;
+}
+
+.input-area :deep(.el-textarea__inner:focus) {
+    border-color: #409eff;
+    box-shadow: none;
+}

+ 128 - 107
src/entrypoints/sidepanel/hook/useMsg.ts

@@ -2,13 +2,12 @@
 import { ref, reactive, nextTick, inject } from 'vue';
 import avator from '@/public/icon/32.png';
 import moment from 'moment'
-import { getFileContent, getFormKey, buildObjPrompt ,getFileSummaryPrompt} from '@/utils/ai-service'
+import {  getFormKey, buildObjPrompt ,getFileSummaryPrompt} from '@/utils/ai-service'
 import { ElMessage } from 'element-plus';
-
+import { getPageInfo } from '../utils/index'
 // import { sendMessage } from '@/utils/ai-service';
-export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Function) {
+export function useMsg(scrollbar?: any) {
     const msgUuid = ref<string>();
-    const inputMessage = ref('');
     const indexTemp = ref(0);
     const taklToHtml = ref<any>(false);
     const sendLoading = ref(false);
@@ -19,94 +18,67 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
     // 获取父组件提供的 Hook 实例
     const {useStore} = inject('indexedDBHook') as any;
 
-
-    const getFileValue = async (file: any, form: any) => {
-    const obj = reactive({
-      id: moment(),
-      username: '用户1',
-      rawContent: '',
-      content: '解析文件中',
-      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
-      isSelf: false,
-      avatar: avator,
-      addToHistory: !taklToHtml.value
-    })
-
+    const getFileSummary = async (file: any) => {
+     const obj = reactive({
+       id: moment(),
+       username: '用户1',
+       rawContent: '',
+       content: '解析文件中',
+       timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+       isSelf: false,
+       avatar: avator,
+       addToHistory: !taklToHtml.value
+     })
     try {
       sendLoading.value = true
       messages.value.push(obj)
       nextTick(() => scrollbar.value?.setScrollTop(99999))
-      let formData = new FormData();
-      formData.append("file", file);
-      const res = await getFileContent(formData)
-      if (type.value === '2') {
-        const response = await getFormKey({
-          body: form,
-          input_data: res.data
-        })
-        xlsxData.value = response.data
-        console.log(xlsxData.value);
-        console.log(type.value);
-
-        await streamRes(buildObjPrompt(response.data, form), false)
-      }
+    const res = await getFileValue(file)
       console.log(res.data, file);
-      
-      if (type.value === '') {
-        console.log(getFileSummaryPrompt(res.data, file.name));
-        
-        await streamRes(getFileSummaryPrompt(res.data, file.name), false)
-      }
+          await streamRes()
     } catch (error) {
-      console.log(error);
-      
       obj.content = '解析出错'
     } finally {
-      
+        sendLoading.value = false
     }
-  }
-    // 发送消息
-    const addMessage = (msg: any, fetch: any) => {
-        if (!msg) return
-        const newMessage: any = {
-            id: messages.value.length + 1,
-            username: '我',
-            content: msg,
+    }
+    const getFormKeyAndValue = async (file: any, form?: any) => {
+        const obj = reactive({
+            id: moment(),
+            username: '用户1',
+            rawContent: '',
+            content: '解析文件中',
             timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
-            isSelf: true,
-            avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
+            isSelf: false,
+            avatar: avator,
             addToHistory: !taklToHtml.value
-        }
-        messages.value.push(newMessage)
-        useStore(msgUuid.value).add(newMessage)
-
-        // 滚动到底部
-        nextTick(() => {
-            scrollbar.value?.setScrollTop(99999);
-            fetch && sendRequese(msg, taklToHtml.value);
         })
-    }
 
-    const getPageInfo = () => {
-        return new Promise((res, rej) => {
-            chrome.runtime.sendMessage({
-                type: 'FROM_SIDE_PANEL_TO_GET_PAGE_INFO',
-            }, async (response) => {
-                if (chrome.runtime.lastError) {
-                    console.error("消息发送错误:", chrome.runtime.lastError);
-                    rej(chrome.runtime.lastError)
-                } else {
-                    pageInfo.value = response.data
-                    res(response.data)
-                }
-            });
-        })
+        try {
+            sendLoading.value = true
+            messages.value.push(obj)
+                const response = await getFormKey({
+                    body: form,
+                    input_data: file
+                })
+            return response
+                xlsxData.value = response.data
+                console.log(xlsxData.value);
+                console.log(type.value);
+                await streamRes(buildObjPrompt(response.data, form))
+        } catch (error) {
+            obj.content = '解析出错'
+        } finally {
+            sendLoading.value = false
+        }
     }
+    // 发送消息
+   
+
+ 
 
     const sendRequese = async (msg: any, addHtml = false) => {
         const res: any = await getPageInfo()
-
-
         if ((type.value === '2' && msg.startsWith('/')) || msg.startsWith('请')) {
             if (!taklToHtml.value) return messages.value.push({
                 id:messages.value.length + 1,
@@ -123,7 +95,7 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
         }
         else {
             if (!addHtml) msg = getSummaryPrompt(res.content)
-            streamRes(msg, addHtml)
+            streamRes(msg)
         }
     }
 
@@ -143,8 +115,79 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
         await fetchDataAndProcess(msg, obj)
         sendLoading.value = false
     }
+    let str = ''
+    async function fetchDataAndProcess(input:any, obj:any) {
+        if (input.startsWith('/智能填表')) {
+            input = input.split('/智能填表')[1]
+        }
+        str = input
+        console.log(str);
+        const pageInfo = await getPageInfo();
+        await new Promise((res:any) => setTimeout(() => {
+            res()
+        }, 2000))
+        // const res = await hepl({
+        //   input_data: input,
+        //   body: pageInfo.content.mainContent
+        // })
+        const res = await new Promise((resolve, reject) => {
+            setTimeout(() => {
+                resolve({ data: pageInfo.title === '智能招采' ? mockData[indexTemp.value] : mockData2[indexTemp.value] })
+            }, 1000)
+        })
+        if (!res.data.tag || res.data.tag === 'undefined') {
+            ElMessage({ message: '未找到标签,请重试', type: 'error', duration: 4 * 1000, grouping: true })
+            obj.content = '未找到标签,请重试'
+            type.value = ''
+            return
+        }
+        await handleClick(res.data, obj);
+    }
+
+
+    async function handleClick(res:any, msgObj:any) {
+        await new Promise(resolve => setTimeout(resolve, 2000))
+        msgObj.content = `点击${res.tag}元素`
+        chrome.runtime.sendMessage({
+            type: 'FROM_SIDE_PANEL_TO_ACTION',
+            data: res
+        }, async ({ data, status }) => {
+            if (chrome.runtime.lastError) {
+                console.error("消息发送错误:", chrome.runtime.lastError);
+            } else {
+                if (status === 'error') {
+                    msgObj.content = data
+                    return
+                }
+                if (res.next === '是') {
+                    const arr = str.split(',')
+                    arr.shift()
+                    str = arr.join(',')
+                    indexTemp.value++
+                    fetchDataAndProcess(str, msgObj)
+                } else {
+                    if (type.value === '2') {
+                        await new Promise((resolve, reject) => {
+                            setTimeout(() => {
+                                resolve(1)
+                            }, 2000)
+                        })
+                        msgObj.content = `请上传数据`
+                        ElMessage({ message: '请上传数据', type: 'success', duration: 4 * 1000, grouping: true })
+                    } else {
+                        msgObj.content = `执行完毕`
+                    }
+                }
+            }
+            return true
+        });
 
-    const streamRes = async (msg: any, addHtml: any) => {
+    }
+    /**
+     * 
+     * @param addHtml 是否添加页面信息
+     */
+    const streamRes = async (addHtml:any = false) => {
         sendLoading.value = true;
         const obj = reactive<any>({
             id:messages.value.length + 1,
@@ -154,7 +197,7 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
             timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
             isSelf: false,
             avatar: avator,
-            addToHistory: !taklToHtml.value
+            addToHistory: !taklToHtml.value,
         });
         let history = []
         if (taklToHtml.value) {
@@ -166,23 +209,23 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
             }
             history.push({
                 role: 'user',
-                content: msg
+                content: messages.value[messages.value.length - 1].rawContent
             })
         } else {
             history = messages.value
                 .filter((item: any) => item.addToHistory).slice(-20)
                 .map((item: any) => ({
                     role: item.isSelf ? 'user' : 'system',
-                    content: item.isSelf ? item.content : item.rawContent
+                    content: item.rawContent
                 }))
+          
         }
 
         messages.value.push(obj)
         nextTick(() => {
             scrollbar.value?.setScrollTop(99999)
         })
-        const iterator = await sendMessage(history, addHtml)
-
+        const iterator = await sendMessage(history)
         for await (const chunk of iterator) {
             if (chunk) {
                 const decodedChunk = chunk.choices[0].delta.content;
@@ -200,47 +243,25 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
         useStore(msgUuid.value).add({...obj})
 
         // 处理最终内容
-        if (type.value === '2') {
-            try {
-                formMap.value = JSON.parse(obj.rawContent.split('json')[1].split('```')[0])
-                handleInput()
-                type.value = ''
-            } catch (e) {
-                console.error('解析JSON失败:', e)
-            }
-        }
-        type.value = ''
         sendLoading.value = false
         nextTick(() => {
             scrollbar.value?.setScrollTop(99999)
         })
     }
 
-  const handleInput = () => {
-    chrome.runtime.sendMessage({
-      type: 'FROM_SIDE_PANEL_TO_INPUT_FORM',
-      data: {
-        excelData: xlsxData.value,
-        formData: formMap.value
-      }
-    });
-  }
+   
 
     return {
         msgUuid,
         messages,
-        inputMessage,
         indexTemp,
         taklToHtml,
-        pageInfo,
         sendLoading,
         formMap,
         type,
-        addMessage,
         sendRequese,
-        getPageInfo,
         streamRes,
-        handleInput,
-        getFileValue
+        getFormKeyAndValue,
+        getFileSummary
     }
 }

+ 1 - 1
src/entrypoints/sidepanel/hook/useSummary.ts

@@ -1,6 +1,6 @@
 export function useSummary(addMessage: Function, sendRequese: Function) {
   const handleCardButtonClick = async () => {
-    addMessage('总结当前页面', false)
+    addMessage('总结当前页面')
     await sendRequese('', false)
   }
 

+ 1 - 1
src/entrypoints/sidepanel/mock.ts

@@ -44,4 +44,4 @@ export const startMsg = {
     timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
     isSelf: false,
     avatar: avator
-}
+}

+ 23 - 0
src/entrypoints/sidepanel/utils/index.js

@@ -0,0 +1,23 @@
+export const getPageInfo = () => {
+    return new Promise((res, rej) => {
+        chrome.runtime.sendMessage({
+            type: 'FROM_SIDE_PANEL_TO_GET_PAGE_INFO',
+        }, async (response) => {
+            if (chrome.runtime.lastError) {
+                console.error("消息发送错误:", chrome.runtime.lastError);
+                rej(chrome.runtime.lastError)
+            } else {
+                res(response.data)
+            }
+        });
+    })
+}
+export const handleInput = (xlsxData, formMap) => {
+    chrome.runtime.sendMessage({
+        type: 'FROM_SIDE_PANEL_TO_INPUT_FORM',
+        data: {
+            excelData: xlsxData,
+            formData: formMap
+        }
+    })
+}

+ 1 - 1
wxt.config.ts

@@ -6,7 +6,7 @@ export default defineConfig({
   srcDir: "src",
   manifest: {
     "name": "派维斯智能体助手",
-    "version": "0.1.6",
+    "version": "0.1.7",
     "permissions": [
       "storage",
       "history",