瀏覽代碼

refactor(sidepanel): 优化智能填表功能

- 移除冗余代码,重构消息处理逻辑
- 优化表单信息获取和展示流程
- 调整智能填表提示样式
- 改进 AI 服务请求和响应处理
chd 5 月之前
父節點
當前提交
222a1ca4c7

+ 1 - 3
src/entrypoints/background.js

@@ -37,10 +37,8 @@ export default defineBackground(() => {
             } else {
               console.log('收到 content script 响应:', response)
               console.log(response, 998)
-
               sendResponse(response)
             }
-            return true
           }
         )
       })
@@ -62,7 +60,7 @@ export default defineBackground(() => {
             }
 
 
-            
+
             return true
           }
         )

+ 40 - 26
src/entrypoints/content.js

@@ -23,6 +23,7 @@ export default defineContentScript({
         }
         let dom = null
         if (message.type === 'GET_TAG_ACTION') {
+          console.log(message.data);
           const data = message.data
           if (0) {
             dom = document.getElementById(data.id)
@@ -44,7 +45,6 @@ export default defineContentScript({
             dom.click()
           }, 1000)
           sendResponse({ data: '完成' })
-          return true
         }
         if (message.type === 'GET_PAGE_FORM') {
           const forms = document.querySelectorAll('form')
@@ -55,45 +55,56 @@ export default defineContentScript({
             })
             return
           }
-          for (const form of forms) {
-            form.style.border = '2px solid red'
+          if (forms.length === 1) {
+            form = forms[0]
+            const cloneForm =  forms[0].cloneNode(true)
+            cloneForm.querySelectorAll('svg').forEach((el) => el.remove())
+            formChildren = [...form.elements]
+            sendResponse({
+              status: 'ok',
+              data: cloneForm.outerHTML
+            })
+            return
+          }
+          sendResponse({
+            status: 'select',
+          })
+          for (const item of forms) {
+            item.style.border = '2px solid red'
             function handleClick(e) {
               e.stopPropagation()
               console.log(this.outerHTML);
               for (const form of forms) {
-                form.style.border = 'none '
+                form.style.border = 'none'
                 form.removeEventListener('click', handleClick, true)
               }
-              const form = this.cloneNode(true)
-              form.querySelectorAll('svg').forEach((el) => el.remove())
+              form = this
+              console.log(form,5855);
+              
+              const cloneForm = this.cloneNode(true)
+              cloneForm.querySelectorAll('svg').forEach((el) => el.remove())
+              formChildren = [...form.elements]
               // sendResponse({
               //   type: 'FROM_CONTENT_TO_SEND_PAGE_FORM',
               //   data: this.outerHTML
               // })
               chrome.runtime.sendMessage({
                 type: 'FROM_CONTENT_TO_SEND_PAGE_FORM',
-                data: form.outerHTML
+                data: cloneForm.outerHTML
               })
             }
-            form.addEventListener("click", handleClick,true)
+            item.addEventListener("click", handleClick, true)
           }
         
-          // if (len) {
-          //   const forms = document.querySelectorAll('form')
-          //   if (len > 1) {
-          //     form = forms[len - 1]
-          //   } else form = forms[0]
-          //   form.querySelectorAll('svg').forEach((el) => el.remove())
-          //   formChildren = [...form.elements]
-          // }
+        
  
-          if (!form) {
-            sendResponse({
-              status: 'error',
-              message: '没有找到表单'
-            })
-            return
-          }
+          // if (!form) {
+          //   sendResponse({
+          //     status: 'error',
+          //     message: '没有找到表单'
+          //   })
+          //   return
+          // }
           // sendResponse({
           //   status: 'ok',
           //   data: form.outerHTML
@@ -118,10 +129,10 @@ export default defineContentScript({
         return true
       }
     )
-
-    
     const handleFillInput = async (data, index) => {
-      console.log(data)
+      console.log(data, 85888)
+      console.log(formChildren,form);
+      
       for (let i = 0; i < data.length; i++) {
         const item = data[i]
         if (item.findBy === 'id') {
@@ -147,7 +158,10 @@ export default defineContentScript({
               }
             }
             if (input) {
+              console.log(input, excelDataA[item.excelColumn]);
+              
               await simulateUserInput(input, excelDataA[item.excelColumn])
+              input.value = '32321312'
             }
           }
           if (item.type === 'radio' || item.type === 'checkbox') {

+ 18 - 27
src/entrypoints/sidepanel/Chat.vue

@@ -62,7 +62,7 @@
             </el-tooltip>
 
             <el-tooltip content="选择后,在输入框描述填表流程" placement="top">
-              <el-button round @click="handelIntelligentFillingClick" :disabled="!taklToHtml">智能填表</el-button>
+              <el-button :class="type === '2' ? 'buttom-clicked' : ''" round @click="handelIntelligentFillingClick" :disabled="!taklToHtml">智能填表</el-button>
             </el-tooltip>
           </div>
         </div>
@@ -116,6 +116,7 @@ const drawerRef = useTemplateRef('historyComponentRef')
 // 获取父组件提供的 Hook 实例
 const { registerStore, useStore } = inject('indexedDBHook')
 const { pageInfoList, messages, msgUuid } = storeToRefs(useMsgStore())
+const formInfo = ref('')
 const {
   taklToHtml,
   sendLoading,
@@ -198,7 +199,12 @@ async function handleAsk() {
   if (sendLoading.value) return
   addMessage(inputMessage.value.trim())
   // handleSend(inputMessage.value.trim())
-  if (type.value === '2') fetchRes(inputMessage.value.trim())
+  if (type.value === '2') {
+    const res = await fetchRes(inputMessage.value.trim())
+    if (res.status === 'ok') formInfo.value = res.data
+    console.log(res, 88452588);
+   
+  }
   else streamRes(true)
   inputMessage.value = ''
   // streamRes(taklToHtml)
@@ -215,43 +221,27 @@ function hisRecords() {
 }
 const handleUpload = async (file) => {
   if (type.value === '2') {
-    chrome.runtime.sendMessage({
-      type: 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM'
-    }, async (response) => {
-      if (chrome.runtime.lastError) {
-        console.error('消息发送错误:', chrome.runtime.lastError)
-      } else {
-        const fileExtension = file.name.split('.').pop().toLowerCase()
-        if (response.status === 'error') return ElMessage({
-          message: response.message,
-          type: 'error',
-          duration: 4 * 1000,
-          grouping: true
-        })
+    const fileExtension = file.name.split('.').pop().toLowerCase()
         if (fileExtension === 'xlsx') {
           const readData = await getXlsxValue(file)
           readData[0].forEach((header, i) => {
             // if (!xlsxData.value[header]) xlsxData.value[header] = []
             xlsxData.value[header] = readData[1][i]
           })
-          addMessage(`已上传文件:${file.name}`, buildExcelUnderstandingPrompt(readData[0], file?.name, response.data))
+          addMessage(`已上传文件:${file.name}`, buildExcelUnderstandingPrompt(readData[0], file?.name, formInfo.value))
           const a = await streamRes()
+          console.log(a);
           handleInput(xlsxData.value, JSON.parse(a.split('json')[1].split('```')[0]))
         } else {
           const { data, msg } = await getFileValue(file)
-          const res2 = await getFormKeyAndValue(data, response.data)
+          const res2 = await getFormKeyAndValue(data, formInfo.value)
           xlsxData.value = res2.data
-          msg.rawContent = buildObjPrompt(res2.data, response.data)
-          console.log()
-
+          msg.rawContent = buildObjPrompt(res2.data, formInfo.value)
           const a = await streamRes()
           handleInput(xlsxData.value, JSON.parse(a.split('json')[1].split('```')[0]))
-          console.log(xlsxData.value)
-          console.log(type.value)
-        }
       }
-      return true
-    })
+          type.value = ''
+        return
   }
   if (type.value === '') {
     const fileVaue = await getFileValue(file)
@@ -292,7 +282,8 @@ onMounted(() => {
       pageInfo.value = message.data
     }
      if (message.type === 'TO_SIDE_PANEL_FORM_INFO') {
-      
+       formInfo.value = message.data
+       messages.value[messages.value.length - 1].content = '请上传数据'
     }
   })
   // 添加标题悬停事件监听
@@ -321,4 +312,4 @@ onMounted(() => {
 
 <style lang="scss" scoped>
 @import '@/entrypoints/sidepanel/css/chat.scss';
-</style>
+</style>@/entrypoints/sidepanel/utils/ai-service.js

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

@@ -316,3 +316,7 @@
   border-color: #409eff;
   box-shadow: none;
 }
+.buttom-clicked {
+    color: #409eff;
+    border-color: rgb(197.7, 225.9, 255);
+}

+ 145 - 27
src/entrypoints/sidepanel/hook/useMsg.ts

@@ -7,7 +7,7 @@ import {
   getFormKey,
   buildObjPrompt,
   getFileSummaryPrompt
-} from '@/utils/ai-service'
+} from '@/utils/ai-service.js'
 import { ElMessage } from 'element-plus'
 import { getPageInfo } from '../utils/index.js'
 import { mockData, mockData2 } from '../mock'
@@ -112,6 +112,30 @@ export function useMsg(scrollbar?: any) {
     messages.value.push(obj)
     msg = msg.split('/智能填表')[1]
     nextTick(() => scrollbar.value?.setScrollTop(99999))
+    if (!msg) {
+      const res = await new Promise((res, rej) => {
+        chrome.runtime.sendMessage({
+          type: 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM'
+        }, ({ status, data }) => {
+          if (status === 'error') {
+            obj.content = '当前页面未找到表单'
+            sendLoading.value = false
+            res({ status })
+          }
+          if (status === 'ok') {
+            obj.content = '请上传数据'
+            sendLoading.value = false
+            res({ status, data })
+          }
+          if (status === 'select') {
+            obj.content = '检测到左侧页面中有多个表单,请选择要填写的表单。'
+            sendLoading.value = false
+            res({ status })
+          }
+        })
+      })
+      return res
+    }
     if (!msg) {
       obj.content = `请选择表单`
       // ElMessage({
@@ -127,18 +151,50 @@ export function useMsg(scrollbar?: any) {
           obj.content = '当前页面未找到表单'
           sendLoading.value = false
         }
+        if (response.status === 'ok') {
+          obj.content = '请上传数据'
+          sendLoading.value = false
+          return
+        }
       })
       return
     }
-    await fetchDataAndProcess(msg, obj)
+    const res = await fetchDataAndProcess(msg, obj)
+    console.log(res);
+    if (res.status === 'ok') {
+      await new Promise((res: any) =>
+        setTimeout(() => {
+          res()
+        }, 2000)
+      )
+      const res = await new Promise((res, rej) => {
+        chrome.runtime.sendMessage({
+          type: 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM'
+        }, ({ status, data }) => {
+          if (status === 'error') {
+            obj.content = '当前页面未找到表单'
+            sendLoading.value = false
+            res({ status })
+          }
+          if (status === 'ok') {
+            obj.content = '请上传数据'
+            sendLoading.value = false
+            res({ status, data })
+          }
+          if (status === 'select') {
+            obj.content = '检测到左侧页面中有多个表单,请选择要填写的表单。'
+            sendLoading.value = false
+            res({ status })
+          }
+        })
+      })
+      return res
+    }
     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()
@@ -151,7 +207,7 @@ export function useMsg(scrollbar?: any) {
     //   input_data: input,
     //   body: pageInfo.content.mainContent
     // })
-    const res = await new Promise((resolve, reject) => {
+    const res: any = await new Promise((resolve, reject) => {
       setTimeout(() => {
         resolve({
           data:
@@ -161,6 +217,7 @@ export function useMsg(scrollbar?: any) {
         })
       }, 1000)
     })
+    const data = res.data
     if (!res.data.tag || res.data.tag === 'undefined') {
       ElMessage({
         message: '未找到标签,请重试',
@@ -169,10 +226,56 @@ export function useMsg(scrollbar?: any) {
         grouping: true
       })
       obj.content = '未找到标签,请重试'
-      type.value = ''
       return
     }
-    await handleClick(res.data, obj)
+    console.log(res);
+
+    await new Promise((resolve) => setTimeout(resolve, 2000))
+    obj.content = `点击${res.data.tag}元素`
+    const res2 = await new Promise((resolve, rej) => {
+      chrome.runtime.sendMessage(
+        {
+          type: 'FROM_SIDE_PANEL_TO_ACTION',
+          data: res.data
+        },
+        async ({ data, status }) => {
+          if (chrome.runtime.lastError) {
+            console.error('消息发送错误:', chrome.runtime.lastError)
+          } else {
+            if (status === 'error') {
+              obj.content = data
+              resolve({ data, status })
+            }
+            if (res.data.next === '是') {
+              const arr = str.split(',')
+              arr.shift()
+              str = arr.join(',')
+              indexTemp.value++
+              const res = await fetchDataAndProcess(str, obj)
+              resolve(res)
+            } else resolve({ status: 'ok' })
+            // else {
+            //   await new Promise((resolve, reject) => {
+            //     setTimeout(() => {
+            //       resolve(1)
+            //     }, 2000)
+            //   })
+            //   obj.content = `请选择表单`
+            //   ElMessage({
+            //     message: '请选择表单',
+            //     type: 'success',
+            //     duration: 4 * 1000,
+            //     grouping: true
+            //   })
+            //   chrome.runtime.sendMessage({
+            //     type: 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM'
+            //   })
+            // }
+          }
+        }
+      )
+    })
+    return res2
   }
 
   async function handleClick(res: any, msgObj: any) {
@@ -198,25 +301,21 @@ export function useMsg(scrollbar?: any) {
             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
-              })
-              chrome.runtime.sendMessage({
-                type: 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM'
-              })
-            } else {
-              msgObj.content = `执行完毕`
-            }
+            await new Promise((resolve, reject) => {
+              setTimeout(() => {
+                resolve(1)
+              }, 2000)
+            })
+            msgObj.content = `请选择表单`
+            ElMessage({
+              message: '请选择表单',
+              type: 'success',
+              duration: 4 * 1000,
+              grouping: true
+            })
+            chrome.runtime.sendMessage({
+              type: 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM'
+            })
           }
         }
         return true
@@ -276,10 +375,14 @@ export function useMsg(scrollbar?: any) {
           obj.rawContent += decodedChunk
           // 实时格式化显示内容
           obj.content = formatMessage(obj.rawContent)
+          if (type.value === '2') obj.content = obj.content.replace(/item/g, '表单项').replace(/excelColumn/g, '对应数据源')
+
         }
       }
       scrollbar.value?.setScrollTop(99999)
     }
+    console.log(obj.rawContent);
+
     //添加到存储历史
     useStore(msgUuid.value).add({ ...obj })
     // 处理最终内容
@@ -287,6 +390,21 @@ export function useMsg(scrollbar?: any) {
     nextTick(() => {
       scrollbar.value?.setScrollTop(99999)
     })
+    console.log();
+    // if (type.value === '2') {
+    //   const arr = JSON.parse(obj.rawContent.split('json')[1].split('```')[0])
+    //   const newArr = arr.map((i:any) => {
+    //     return {
+    //       '表单项': i.label ?? i.placeholder,
+    //       '对应数据': i.excleColumn
+    //     }
+    //   })
+    //   obj.content = formatMessage('```json' + JSON.stringify(newArr) + '```')
+    //   console.log(formatMessage('```json' + JSON.stringify(newArr) + '```'));
+
+    // }
+    console.log(obj.content);
+
     return obj.rawContent
   }
   return {

+ 3 - 87
src/entrypoints/sidepanel/utils/index.js

@@ -56,90 +56,6 @@ export function getXlsxValue (file) {
     }
   })
 }
-let indexTemp = 0
-export async function handleClick(res, msgObj,input) {
-  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 = input.split(',')
-          arr.shift()
-          const input = arr.join(',')
-          indexTemp++
-          fetchDataAndProcess(input, 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
-            })
-            chrome.runtime.sendMessage({
-              type: 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM'
-            })
-          } else {
-            msgObj.content = `执行完毕`
-          }
-        }
-      }
-      return true
-    }
-  )
-}
-async function fetchDataAndProcess(input, obj,pageInfo) {
-  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
-  // })
-  const res = await new Promise((resolve, reject) => {
-    setTimeout(() => {
-      resolve({
-        data:
-          pageInfo.title === '智能招采'
-            ? mockData[indexTemp]
-            : mockData2[indexTemp]
-      })
-    }, 1000)
-  })
-  if (!res.data.tag || res.data.tag === 'undefined') {
-    ElMessage({
-      message: '未找到标签,请重试',
-      type: 'error',
-      duration: 4 * 1000,
-      grouping: true
-    })
-    obj.content = '未找到标签,请重试'
-    return
-  }
-  await handleClick(res.data, obj,input)
-}
+
+
+

+ 6 - 4
src/utils/ai-service.js

@@ -225,10 +225,11 @@ ${pageInfo}
 2. 生成表单项与列标题对应的数组,并使用findBy告诉我通过表单项的什么字段信息匹配到的,使用findByValue告诉我匹配到的表单项字段值,使用excelColumn字段告诉我excel文件中列标题的值。
 3. 表单项有id根据id匹配,findBy是id,并通过findByValue告诉我id的值,没有id根据label匹配,findBy是label,并通过findByValue给我label元素的值,没有label根据placeholder匹配,findBy是placeholder,并通过findByValue告诉我placeholder的值,没有placeholder,再根据其他内容匹配
 3. 并去除没有匹配到的表单项和excel文件中没有匹配到的列,
-4. 通过type字段告诉我输入项的类型
-5. 返回数组,不要返回任何其他内容。`
+4. 通过type字段告诉我输入项的类型,表单项有label,通过item字段返回label的值。
+5. 返回json格式数组,不要返回任何其他内容。`
 }
 
+
 // 5. 如果表单项有label标签,同时返回label, 通过label字段告诉我label元素的文本
 export function buildObjPrompt(obj, pageInfo) {
   return `我将向你展示一个对象和一个form表单。请帮我理解这些数据:
@@ -242,8 +243,9 @@ ${pageInfo}
 2. 表单项有label,根据label匹配,没有label根据placeholder匹配,没有placeholder,根据id匹配,再根据其他内容匹配
 3. 并根据实际可操作的表单项的所有信息与上传的对象的key进行匹配,生成表单项与key的数组,并使用findBy告诉我通过表单项的什么字段信息匹配到的,使用findByValue告诉我匹配到的表单项字段值,使用excelColumn字段告诉我对应的key值。在一个字段内返回
 4. 并去除没有匹配到的表单项和对象中没有匹配到的key,
-5. 通过type字段告诉我输入项的类型,如果对象中key对应的是日期,type统一返回date
-6. 仅返回数组,不要返回任何其他内容。`
+5. 通过type字段告诉我输入项的类型,如果对象中key对应的是日期,type统一返回date。
+6. 表单项有label,通过item字段返回label的值。
+7. 返回json格式返回数组,不要返回任何其他内容。`
 }
 
 function escapeHtml(html) {

+ 3 - 1
src/utils/contentUtils.js

@@ -132,7 +132,9 @@ export async  function simulateCompleteUserAction  (
         throw error
     }
 }
-export async function simulateUserInput (element, value){
+export async function simulateUserInput(element, value) {
+    console.log(35656);
+    
     // 设置值
     if (element.tagName.toLowerCase() === 'textarea') {
         element.focus()