瀏覽代碼

合并 chd分支

wzg 5 月之前
父節點
當前提交
448d4c9551

+ 6 - 7
src/entrypoints/background.js

@@ -18,9 +18,6 @@ export default defineBackground(() => {
         
         if (message.type === 'FROM_SIDE_PANEL_TO_ACTION') {
             console.log(565888);
-            chrome.tabs.query({ active: true }, (tabs) => {
-                console.log(tabs);
-            });
             chrome.tabs.query({ active: true }, (tabs) => {
                 console.log(tabs);
                 
@@ -31,9 +28,11 @@ export default defineBackground(() => {
                         console.error("消息发送失败:", chrome.runtime.lastError.message);
                     } else {
                         console.log("收到 content script 响应:", response);
-                        sendResponse(response.data)
+                        console.log(response,998);
+                        
+                        sendResponse(response)
                     }
-
+                    return true
                 });
             });
             return true
@@ -47,7 +46,7 @@ export default defineBackground(() => {
                         console.error("消息发送失败:", chrome.runtime.lastError.message);
                     } else {
                         console.log("收到 content script 响应:", response);
-                        sendResponse(response.data)
+                        sendResponse(response)
                     }
 
                 });
@@ -55,7 +54,7 @@ export default defineBackground(() => {
             return true
         } 
         if (message.type === 'FROM_SIDE_PANEL_TO_INPUT_FORM') {
-            chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
+            chrome.tabs.query({ active: true }, (tabs) => {
                 if (tabs.length === 0) return; // 确保有活动标签页
                 const tabId = tabs[0].id; // 获取当前活动的 tabId
                 chrome.tabs.sendMessage(tabId, { type: "INPUT_FORM", data: message.data }, (response) => {

+ 402 - 327
src/entrypoints/content.js

@@ -1,348 +1,423 @@
 // entrypoints/content.ts
-import { Loading } from 'element-plus/es/components/loading/src/service.mjs';
-import src1 from '../assets/images/begin.png'
-import PageAnalyzer from '../utils/page-analyzer'
-import { log } from 'console';
+import PageAnalyzer, { cleanPage } from '../utils/page-analyzer'
 
 export default defineContentScript({
-  matches: ["<all_urls>"],
-  main(ctx) {
-    let page = document.getElementsByTagName('body')[0];
-    const src = chrome.runtime.getURL('images/begin.png')
-    window.pageAnalyzer = new PageAnalyzer();
-    window.onload = () => {
-      // chrome.runtime.sendMessage(getPageInfo())
-    }
-    let form = null
-    let formChildren = []
-    let excelDataA = {}
-    chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
-      if (message.type === 'GET_PAGE_INFO') {
-        sendResponse({
-          data: getPageInfo()
-        })
-      }
-      let dom = null
-      if (message.type === "GET_TAG_ACTION") {
-        const data = message.data
-        if (data.id) {
-          dom = document.getElementById(data.id)
-        }
-        if (data.class) {
-          dom = [...document.getElementsByTagName(data.tag)]
-            // .filter(_ => _.className.includes(data.class))
-            .filter(_ => _.innerText.includes(data.text))
-        }
-        console.log(dom);
-        dom[0].click()
-        sendResponse({ data: '完成' })
-        return true
-      }
-
-      if (message.type === 'GET_PAGE_FORM') {
-
-        const len = document.querySelectorAll("form").length
-        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 && document.querySelector("input")) {
-        //     const arr = []
-        //     const inputs = document.querySelectorAll("input")
-        //     formChildren = [...inputs]
-
-        //     for (const element of inputs) {
-        //         arr.push(element.outerHTML)
-        //     }
-        //     form = { outerHTML: JSON.stringify(arr) }
-        // }
-        if (!form) {
-          sendResponse({
-            status: 'error',
-            message: '没有找到表单'
-          })
-          return
+    matches: ["<all_urls>"],
+    main(ctx) {
+        let page = document.getElementsByTagName('body')[0];
+        const src = chrome.runtime.getURL('images/begin.png')
+        window.pageAnalyzer = new PageAnalyzer();
+        window.onload = () => {
+            chrome.runtime.sendMessage(getPageInfo())
+            console.log(document.title);
+
         }
-        sendResponse({
-          status: 'ok',
-          data: form.outerHTML
-        })
-      }
-      if (message.type === "INPUT_FORM") {
-        const { formData, excelData } = message.data
-        excelDataA = excelData
-        console.log(formData, excelData);
-        await handleFillInput(formData, 0)
-      }
-      return true
-    });
-    function getPageInfo() {
-      const favIconUrl = getFavicon()
-      return {
-        type: "PAGE_INFO",
-        data: {
-          favIconUrl,
-          title: document.title,
-          url: window.location.href,
-          content: window.pageAnalyzer.analyzePage()
-        },
-      }
-    }
-    function getFavicon() {
-      // 尝试获取动态favicon
-      const iconLinks = Array.from(
-        document.querySelectorAll('link[rel*="icon"]')
-      );
-      const favIconUrl = iconLinks
-        .sort((a, b) => {
-          // 优先使用大尺寸图标
-          const sizeA = parseInt(a.sizes?.value) || 0;
-          const sizeB = parseInt(b.sizes?.value) || 0;
-          return sizeB - sizeA;
-        })
-        .map((link) => link.href)
-        .find(Boolean);
-
-      if (favIconUrl) return favIconUrl;
-
-      // 如果没有找到,返回网站根目录的favicon.ico
-      const url = new URL(window.location.href);
-      return `${url.protocol}//${url.hostname}/favicon.ico`;
-    }
-    const handleFillInput = async (data, index) => {
-      console.log(data);
-
-      for (let i = 0; i < data.length; i++) {
-        const item = data[i]
-        if (item.findBy === 'id') {
-          const input = formChildren.find(child => child.id === item.findByValue)
-          if (item.type === 'text' || item.type === 'textarea' || item.type === 'number') {
-            if (!input) {
-              if (item.label) {
-                const label = [...form.getElementsByTagName('label')].find(label => label.innerText.includes(item.label))
-                if (label) {
-                  const input = findLabelForInput(label)
-                  if (input) {
-                    await simulateUserInput(input, excelDataA[item.excelColumn][index])
-                  }
-                }
-              }
+        let form = null
+        let formChildren = []
+        let excelDataA = {}
+        chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
+            if (message.type === 'GET_PAGE_INFO') {
+                sendResponse({
+                    data: getPageInfo()
+                })
             }
-            if (input) {
-              await simulateUserInput(input, excelDataA[item.excelColumn][index])
+            let dom = null
+            if (message.type === "GET_TAG_ACTION") {
+                const data = message.data
+                if (0) {
+                    dom = document.getElementById(data.id)
+                } else {
+                    dom = [...document.getElementsByTagName(data.tag.toLowerCase())]
+                        // .filter(_ => _.className.includes(data.class))
+                        .filter(_ => _.innerText.includes(data.text))[0]
+                }
+                console.log(dom);
+                if (!dom) {
+                    sendResponse({ data: '未找到元素,请重试', statue: 'error' })
+                    return
+                }
+                // 添加红色边框,500ms后移除边框,然后点击
+                const originalBorder = dom.style.border;
+                dom.style.border = '2px solid red';
+                setTimeout(() => {
+                    dom.style.border = originalBorder;
+                    dom.click();
+                }, 1000);
+                sendResponse({ data: '完成' })
+                return true
             }
-          }
-          if (item.type === 'radio' || item.type === 'checkbox') {
-            if (item.label) {
-
-              const label = [...form.getElementsByTagName('label')].find(label => label.innerText.includes(item.label))
-              if (label) {
-                const span = findLabelForSpan(label)
-                span.forEach(span => {
-                  span.innerText === excelDataA[item.excelColumn][index] && span.click()
+
+            if (message.type === 'GET_PAGE_FORM') {
+
+                const len = document.querySelectorAll("form").length
+                if (document.title === '智能招采' && len === 1) {
+                    sendResponse({
+                        status: 'error',
+                        message: '没有找到表单'
+                    })
+                    return
+                }
+
+                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 && document.querySelector("input")) {
+                //     const arr = []
+                //     const inputs = document.querySelectorAll("input")
+                //     formChildren = [...inputs]
+
+                //     for (const element of inputs) {
+                //         arr.push(element.outerHTML)
+                //     }
+                //     form = { outerHTML: JSON.stringify(arr) }
+                // }
+                if (!form) {
+                    sendResponse({
+                        status: 'error',
+                        message: '没有找到表单'
+                    })
+                    return
+                }
+                sendResponse({
+                    status: 'ok',
+                    data: form.outerHTML
                 })
-              }
             }
-          }
+            if (message.type === "INPUT_FORM") {
+                const { formData, excelData } = message.data
+                excelDataA = excelData
+                console.log(formData, excelDataA);
+                await handleFillInput(formData, 0)
+            }
+            return true
+        });
+        function getPageInfo() {
+            const favIconUrl = getFavicon()
+            return {
+                type: "PAGE_INFO",
+                data: {
+                    favIconUrl,
+                    title: document.title,
+                    url: window.location.href,
+                    content: window.pageAnalyzer.analyzePage()
+                },
+            }
+        }
+        function getFavicon() {
+            // 尝试获取动态favicon
+            const iconLinks = Array.from(
+                document.querySelectorAll('link[rel*="icon"]')
+            );
+            const favIconUrl = iconLinks
+                .sort((a, b) => {
+                    // 优先使用大尺寸图标
+                    const sizeA = parseInt(a.sizes?.value) || 0;
+                    const sizeB = parseInt(b.sizes?.value) || 0;
+                    return sizeB - sizeA;
+                })
+                .map((link) => link.href)
+                .find(Boolean);
 
-          if (item.type === 'date') {
-            const input = formChildren.find(child => child.id === item.findByValue)
-            if (excelDataA[item.excelColumn][index]) {
+            if (favIconUrl) return favIconUrl;
 
-              await simulateCompleteUserAction(input, input, formatDate(excelDataA[item.excelColumn][index]), formatDate(excelDataA[item.excelColumn][index]))
+            // 如果没有找到,返回网站根目录的favicon.ico
+            const url = new URL(window.location.href);
+            return `${url.protocol}//${url.hostname}/favicon.ico`;
+        }
+        const handleFillInput = async (data, index) => {
+            console.log(data);
+
+            for (let i = 0; i < data.length; i++) {
+                const item = data[i]
+                if (item.findBy === 'id') {
+                    const input = formChildren.find(child => child.id === item.findByValue)
+                    if (item.type === 'text' || item.type === 'textarea' || item.type === 'number') {
+                        if (!input) {
+                            if (item.label) {
+                                const label = [...form.getElementsByTagName('label')].find(label => label.innerText.includes(item.label))
+                                if (label) {
+                                    const input = findLabelForInput(label)
+                                    if (input) {
+                                        await simulateUserInput(input, excelDataA[item.excelColumn])
+                                    }
+                                }
+                            }
+                        }
+                        if (input) {
+                            await simulateUserInput(input, excelDataA[item.excelColumn])
+                        }
+                    }
+                    if (item.type === 'radio' || item.type === 'checkbox') {
+                        if (item.label) {
+
+                            const label = [...form.getElementsByTagName('label')].find(label => label.innerText.includes(item.label))
+                            if (label) {
+                                const span = findLabelForSpan(label)
+                                span.forEach(span => {
+                                    span.innerText === excelDataA[item.excelColumn] && span.click()
+                                })
+                            }
+                        }
+                    }
+
+                    if (item.type === 'date') {
+                        
+                        const input = formChildren.find(child => child.id === item.findByValue)
+                        if (excelDataA[item.excelColumn]) {
+
+                            await simulateCompleteUserAction(input, input, formatDate(excelDataA[item.excelColumn]), formatDate(excelDataA[item.excelColumn]))
+                        }
+                    }
+                }
+                if (item.findBy === 'placeholder') {
+                    const input = formChildren.find(child => child.placeholder === item.findByValue)
+                    if (input) {
+                        simulateUserInput(input, excelDataA[item.excelColumn])
+                    }
+                }
+                if (item.findBy === 'label') {
+                    if (!excelDataA[item.excelColumn]) continue
+                    const label = [...form.getElementsByTagName('label')].find(label => label.innerText.includes(item.findByValue) || item.findByValue.includes(label.innerText))
+                    console.log(label)
+                    if (!label) continue
+                    if (item.type === 'radio' || item.type === 'checkbox') {
+                        console.log(excelDataA[item.excelColumn]);
+                        
+                        if (label) {
+                            const span = findLabelForSpan(label)
+                            span.forEach(span => {
+                                console.log(span.innerText);
+                                if (span.innerText) {
+                                    if (span.innerText.includes(excelDataA[item.excelColumn]) || excelDataA[item.excelColumn].includes(span.innerText)) {
+                                        console.log(span);
+                                        span.click()
+                                    }     
+                                }
+                            })
+                        }
+                    }
+
+                    if (item.type === 'date') {
+                        const input = findLabelForInput(label)
+                        console.log(input, excelDataA[item.excelColumn]);
+                        
+                        if (input) {
+                            await simulateCompleteUserAction(input, input, formatDate(excelDataA[item.excelColumn]), formatDate(excelDataA[item.excelColumn]))
+                        }
+                    }
+
+                    if (item.type === 'input' || item.type === 'text' || item.type === 'number' || item.type === 'tel' || item.type === 'email') {
+                        const input = findLabelForInput(label)
+                        if (input) {
+                            console.log(excelDataA[item.excelColumn]);
+
+                            await simulateUserInput(input, excelDataA[item.excelColumn])
+                        }
+                    }
+                    if (item.type === 'select') {
+                        const input = findLabelForInput(label)
+                        if (input) {
+                            await simulateUserInput(input, excelDataA[item.excelColumn])
+                        }
+                    }
+                }
             }
-          }
-        } else if (item.findBy === 'placeholder') {
-          const input = formChildren.find(child => child.placeholder === item.findByValue)
-          if (input) {
-            simulateUserInput(input, excelDataA[item.excelColumn][index])
-          }
         }
-      }
-    }
-    const simulateUserInput = async (element, value) => {
-      // 设置值
-      // if (element.tagName.toLowerCase() === 'textarea') {
-      //   element.focus()
-      //   element.value = value
-      //   element.blur()
-      //   return
-      // }
-      element.value = value;
-
-      // 创建并触发 input 事件
-      const inputEvent = new Event('input', { bubbles: true });
-      element.dispatchEvent(inputEvent);
-
-      // 创建并触发 change 事件
-      const changeEvent = new Event('change', { bubbles: true });
-      element.dispatchEvent(changeEvent);
-
-      // 可选:如果表单使用了 React/Vue 等框架,可能还需要触发以下事件
-      element.dispatchEvent(new Event('blur'));
-      element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' }));
-    }
-    const findLabelForInput = (label) => {
-      let p = label.parentElement
-      for (let i = 0; i < 10; i++) {
-        const input = p.getElementsByTagName('input')
-        if (input.length > 0) {
-          return input[0]
+        const simulateUserInput = async (element, value) => {
+            // 设置值
+            // if (element.tagName.toLowerCase() === 'textarea') {
+            //   element.focus()
+            //   element.value = value
+            //   element.blur()
+            //   return
+            // }
+            element.value = value;
+
+            // 创建并触发 input 事件
+            const inputEvent = new Event('input', { bubbles: true });
+            element.dispatchEvent(inputEvent);
+
+            // 创建并触发 change 事件
+            const changeEvent = new Event('change', { bubbles: true });
+            element.dispatchEvent(changeEvent);
+
+            // 可选:如果表单使用了 React/Vue 等框架,可能还需要触发以下事件
+            element.dispatchEvent(new Event('blur'));
+            element.dispatchEvent(new KeyboardEvent('keyup', { key: 'Enter' }));
         }
-        p = p.parentElement
-      }
-      return null
-    }
-    const findLabelForSpan = (label) => {
-      let p = label.parentElement
-      for (let i = 0; i < 10; i++) {
-        const span = p.getElementsByTagName('span')
-        if (span.length > 0) {
-          return [...span]
+        const findLabelForInput = (label) => {
+            let p = label.parentElement
+            for (let i = 0; i < 10; i++) {
+                const input = p.getElementsByTagName('input')
+                if (input.length > 0) {
+                    return input[0]
+                }
+                p = p.parentElement
+            }
+            return null
         }
-        p = p.parentElement
-      }
-      return null
-    }
-    const simulateCompleteUserAction = async (clickElement, inputElement, inputText, tdTitle) => {
-      // 1. 模拟鼠标弹起事件
-      const simulateMouseUp = (element) => {
-        const mouseUpEvent = new MouseEvent('mouseup', {
-          bubbles: true,
-          cancelable: true,
-          view: window,
-          button: 0,
-          buttons: 0,
-          clientX: 0,
-          clientY: 0,
-          detail: 1
-        });
-        element.dispatchEvent(mouseUpEvent);
-      };
-      // 123456qq?
-      // 2. 模拟键盘输入
-      const simulateTyping = async (element, text, delay = 50) => {
-        element.focus();
-        for (let char of text) {
-          await new Promise(resolve => setTimeout(resolve, delay));
-
-          // 按键按下
-          const keydownEvent = new KeyboardEvent('keydown', {
-            key: char,
-            code: `Key${char.toUpperCase()}`,
-            bubbles: true,
-            cancelable: true
-          });
-          element.dispatchEvent(keydownEvent);
-
-          // 更新输入值
-          element.value += char;
-
-          // 触发输入事件
-          const inputEvent = new InputEvent('input', {
-            bubbles: true,
-            cancelable: true,
-            data: char,
-            inputType: 'insertText'
-          });
-          element.dispatchEvent(inputEvent);
-
-          // 按键弹起
-          const keyupEvent = new KeyboardEvent('keyup', {
-            key: char,
-            code: `Key${char.toUpperCase()}`,
-            bubbles: true,
-            cancelable: true
-          });
-          element.dispatchEvent(keyupEvent);
+        const findLabelForTag = (label, tag) => {
+            let p = label.parentElement
+            for (let i = 0; i < 10; i++) {
+                const input = p.getElementsByTagName('input')
+                if (input.length > 0) {
+                    return input[0]
+                }
+                p = p.parentElement
+            }
+            return null
         }
-
-        // 触发change事件
-        element.dispatchEvent(new Event('change', { bubbles: true }));
-      };
-
-      // 3. 查找td元素
-      const findTdByTitle = (title, timeout = 5000) => {
-        return new Promise((resolve, reject) => {
-          const startTime = Date.now();
-
-          const find = () => {
-            const td = document.querySelector(`td[title="${title}"]`);
-            if (td) {
-              resolve(td);
-              return;
+        const findLabelForSpan = (label) => {
+            let p = label.parentElement
+            for (let i = 0; i < 10; i++) {
+                const span = p.getElementsByTagName('span')
+                if (span.length > 0) {
+                    return [...span]
+                }
+                p = p.parentElement
             }
+            return null
+        }
+        const simulateCompleteUserAction = async (clickElement, inputElement, inputText, tdTitle) => {
+            // 1. 模拟鼠标弹起事件
+            const simulateMouseUp = (element) => {
+                const mouseUpEvent = new MouseEvent('mouseup', {
+                    bubbles: true,
+                    cancelable: true,
+                    view: window,
+                    button: 0,
+                    buttons: 0,
+                    clientX: 0,
+                    clientY: 0,
+                    detail: 1
+                });
+                element.dispatchEvent(mouseUpEvent);
+            };
+            // 123456qq?
+            // 2. 模拟键盘输入
+            const simulateTyping = async (element, text, delay = 50) => {
+                element.focus();
+                for (let char of text) {
+                    await new Promise(resolve => setTimeout(resolve, delay));
+
+                    // 按键按下
+                    const keydownEvent = new KeyboardEvent('keydown', {
+                        key: char,
+                        code: `Key${char.toUpperCase()}`,
+                        bubbles: true,
+                        cancelable: true
+                    });
+                    element.dispatchEvent(keydownEvent);
+
+                    // 更新输入值
+                    element.value += char;
+
+                    // 触发输入事件
+                    const inputEvent = new InputEvent('input', {
+                        bubbles: true,
+                        cancelable: true,
+                        data: char,
+                        inputType: 'insertText'
+                    });
+                    element.dispatchEvent(inputEvent);
+
+                    // 按键弹起
+                    const keyupEvent = new KeyboardEvent('keyup', {
+                        key: char,
+                        code: `Key${char.toUpperCase()}`,
+                        bubbles: true,
+                        cancelable: true
+                    });
+                    element.dispatchEvent(keyupEvent);
+                }
 
-            if (Date.now() - startTime > timeout) {
-              reject(new Error(`未找到title为"${title}"的td元素`));
-              return;
+                // 触发change事件
+                element.dispatchEvent(new Event('change', { bubbles: true }));
+            };
+
+            // 3. 查找td元素
+            const findTdByTitle = (title, timeout = 5000) => {
+                return new Promise((resolve, reject) => {
+                    const startTime = Date.now();
+
+                    const find = () => {
+                        const td = document.querySelector(`td[title="${title}"]`);
+                        if (td) {
+                            resolve(td);
+                            return;
+                        }
+
+                        if (Date.now() - startTime > timeout) {
+                            reject(new Error(`未找到title为"${title}"的td元素`));
+                            return;
+                        }
+
+                        requestAnimationFrame(find);
+                    };
+
+                    find();
+                });
+            };
+
+            // 4. 模拟点击事件
+            const simulateClick = (element) => {
+                const clickEvent = new MouseEvent('click', {
+                    bubbles: true,
+                    cancelable: true,
+                    view: window,
+                    detail: 1
+                });
+                element.dispatchEvent(clickEvent);
+            };
+
+            try {
+                // 执行操作序列
+
+                // 1. 触发鼠标弹起
+                simulateMouseUp(clickElement);
+                await new Promise(resolve => setTimeout(resolve, 100));
+
+                // 2. 模拟键盘输入
+                await simulateTyping(inputElement, inputText);
+                await new Promise(resolve => setTimeout(resolve, 200));
+
+                // 3. 查找并点击td元素
+                // const tdElement = await findTdByTitle(tdTitle);
+
+                const enterKeyEvent = new KeyboardEvent('keydown', {
+                    key: 'Enter',       // 事件键名
+                    code: 'Enter',      // 物理按键编码
+                    keyCode: 13,        // 传统键码(Enter键为13)
+                    which: 13,          // 同keyCode
+                    bubbles: true,      // 允许事件冒泡
+                    cancelable: true    // 允许事件被取消
+                });
+                setTimeout(() => {
+                    inputElement.dispatchEvent(enterKeyEvent);
+                }, 0)
+                await new Promise(resolve => setTimeout(resolve, 500));
+                return true;
+            } catch (error) {
+                throw error;
             }
+        };
+        function formatDate(date) {
+            // 直接创建北京时间的日期对象
+            const d = new Date(date);
 
-            requestAnimationFrame(find);
-          };
+            // 获取年、月、日
+            const year = d.getFullYear();
+            const month = String(d.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要加1
+            const day = String(d.getDate()).padStart(2, '0');
 
-          find();
-        });
-      };
-
-      // 4. 模拟点击事件
-      const simulateClick = (element) => {
-        const clickEvent = new MouseEvent('click', {
-          bubbles: true,
-          cancelable: true,
-          view: window,
-          detail: 1
-        });
-        element.dispatchEvent(clickEvent);
-      };
-
-      try {
-        // 执行操作序列
-
-        // 1. 触发鼠标弹起
-        simulateMouseUp(clickElement);
-        await new Promise(resolve => setTimeout(resolve, 100));
-
-        // 2. 模拟键盘输入
-        await simulateTyping(inputElement, inputText);
-        await new Promise(resolve => setTimeout(resolve, 200));
-
-        // 3. 查找并点击td元素
-        // const tdElement = await findTdByTitle(tdTitle);
-
-        const enterKeyEvent = new KeyboardEvent('keydown', {
-          key: 'Enter',       // 事件键名
-          code: 'Enter',      // 物理按键编码
-          keyCode: 13,        // 传统键码(Enter键为13)
-          which: 13,          // 同keyCode
-          bubbles: true,      // 允许事件冒泡
-          cancelable: true    // 允许事件被取消
-        });
-        setTimeout(() => {
-          inputElement.dispatchEvent(enterKeyEvent);
-        }, 0)
-        await new Promise(resolve => setTimeout(resolve, 500));
-        return true;
-      } catch (error) {
-        throw error;
-      }
-    };
-    function formatDate(date) {
-      // 直接创建北京时间的日期对象
-      const d = new Date(date);
-
-      // 获取年、月、日
-      const year = d.getFullYear();
-      const month = String(d.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要加1
-      const day = String(d.getDate()).padStart(2, '0');
-
-      return `${year}-${month}-${day}`;
-    }
-
-  },
+            return `${year}-${month}-${day}`;
+        }
+
+    },
 });

+ 116 - 98
src/entrypoints/sidepanel/Chat.vue

@@ -36,14 +36,14 @@
       <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;"/>
+            <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/>
+              <CircleClose />
             </el-icon>
           </div>
           <div class="card-btn">
@@ -80,17 +80,16 @@
 import {ref, onMounted, nextTick, inject, useTemplateRef} from 'vue'
 import {ElScrollbar, ElAvatar, ElInput, ElButton} from 'element-plus'
 import moment from "moment";
-import {buildExcelUnderstandingPrompt} from '@/utils/ai-service.js'
+import { buildExcelUnderstandingPrompt ,getFileContent} 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} from "@/entrypoints/sidepanel/mock"
+import {mockData, startMsg, mockData2} from "@/entrypoints/sidepanel/mock"
 import {useAutoResizeTextarea} from '@/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts';
 
-
 // 滚动条引用
 const scrollbar = ref(null);
 const xlsxData = ref({});
@@ -112,17 +111,14 @@ const {
   sendRequese,
   getPageInfo,
   streamRes,
-  handleInput
+  handleInput,
+  getFileValue
 } = useMsg(scrollbar, xlsxData, fetchDataAndProcess);
 const {handleCardButtonClick} = useSummary(addMessage, sendRequese);
 
 function handelIntelligentFillingClick() {
-  if (type.value !== '2') {
-    inputMessage.value = '/智能填表 '
-    type.value = '2'
-  } else {
-    type.value = ''
-  }
+  inputMessage.value = '/智能填表 '
+  type.value = '2'
 }
 
 function handleCurrentData(e) {
@@ -186,120 +182,142 @@ let formInfo = []
 const flag = ref(false)  //true调用算法接口
 
 const handleUpload = (file) => {
-  chrome.runtime.sendMessage({
+  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 {
       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
-      const reader = new FileReader();
-      reader.readAsArrayBuffer(file);
-      reader.onload = async (e) => {
-        const data = new Uint8Array(e.target.result);
-        const workbook = XLSX.read(data, {
-          type: "array",
-          cellDates: false,
-          cellNF: true,
-          cellText: true,
-          dateNF: 'yyyy-mm-dd'
-        });
-
-        // 修复日期处理
-        const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
-
-        // 转换为JSON数据
-        const readData = XLSX.utils.sheet_to_json(firstSheet, {
-          header: 1,
-          raw: false,
-          defval: "",
-          dateNF: 'yyyy-mm-dd'
-        });
-        console.log(readData, 58);
-
-        readData[0].forEach((header, i) => {
-          if (!xlsxData.value[header]) xlsxData.value[header] = []
-          xlsxData.value[header].push(readData[1][i])
-        })
-        if (type.value === '2') {
-          await streamRes(buildExcelUnderstandingPrompt(readData, file?.name, response), false)
-        }
-      };
+      if (fileExtension === 'xlsx') {
+        const reader = new FileReader();
+        reader.readAsArrayBuffer(file);
+        reader.onload = async (e) => {
+          const data = new Uint8Array(e.target.result);
+          const workbook = XLSX.read(data, {
+            type: "array",
+            cellDates: false,
+            cellNF: true,
+            cellText: true,
+            dateNF: 'yyyy-mm-dd'
+          });
+
+          // 修复日期处理
+          const firstSheet = workbook.Sheets[workbook.SheetNames[0]];
+
+          // 转换为JSON数据
+          const readData = XLSX.utils.sheet_to_json(firstSheet, {
+            header: 1,
+            raw: false,
+            defval: "",
+            dateNF: 'yyyy-mm-dd'
+          });
+          console.log(readData, 58);
+
+          readData[0].forEach((header, i) => {
+            // if (!xlsxData.value[header]) xlsxData.value[header] = []
+            xlsxData.value[header] = readData[1][i]
+          })
+          if (type.value === '2') {
+            await streamRes(buildExcelUnderstandingPrompt(readData, file?.name, response), false)
+          }
+        };
+      } 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);
+      }
+
     }
     return true
   });
 
-}
+  }
+  if (type.value === '') {
 
+  }
+}
+let str = ''
 async function fetchDataAndProcess(input, obj) {
-  // console.log(input);
-
-  // const pageInfo = await getPageInfo();
-
-  // 发起请求获取数据
+  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
+  //   input_data: input,
+  //   body: pageInfo.content.mainContent
   // })
+  console.log(pageInfo.title);
+
   const res = await new Promise((resolve, reject) => {
     setTimeout(() => {
-      resolve({data: mockData[indexTemp.value]})
+      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, 1000))
-  if (res.action === 'click') {
-    msgObj.content = `点击${res.tag}元素`
-    chrome.runtime.sendMessage({
-      type: 'FROM_SIDE_PANEL_TO_ACTION',
-      data: res
-    }, async (response) => {
-      if (chrome.runtime.lastError) {
-        console.error("消息发送错误:", chrome.runtime.lastError);
-        rej(chrome.runtime.lastError)
+  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 (res.next === '是') {
-          indexTemp.value++
-          fetchDataAndProcess('', msgObj)
+        if (type.value === '2') {
+           await new Promise((resolve, reject) => {
+    setTimeout(() => {
+      resolve()
+    }, 2000)
+  })
+          msgObj.content = `请上传数据`
+          ElMessage({ message: '请上传数据', type: 'success', duration: 4 * 1000, grouping: true })
         } else {
-          ElMessage({message: '操作执行完成', type: 'success', duration: 2 * 1000, grouping: true})
-          // index = 0
+          msgObj.content = `执行完毕`
         }
       }
-      return true
-    });
-  }
-  if (res.action === 'show') {
-    msgObj.content = `请上传数据`
-    ElMessage({message: '请上传数据', type: 'success', duration: 4 * 1000, grouping: true})
-  }
-  //     chrome.runtime.sendMessage({
-  //          type: 'FROM_SIDE_PANEL_TO_ACTION',
-  //                 data:obj
-  //     }, async (response) => {
-  //         if (chrome.runtime.lastError) {
-  //             console.error("消息发送错误:", chrome.runtime.lastError);
-  //             rej(chrome.runtime.lastError)
-  //         } else {
-  //             if (obj.next === '是') {
-  //                 console.log(strArr[index]);
-
-  //                 index++
-  //                 fetchDataAndProcess(strArr[index])
-  //             } else {
-  //                 ElMessage({ message: '操作执行完成', type: 'success', duration: 2 * 1000, grouping: true })
-  //                 index = 0
-  //             }
-  //         }
-  //         return true
-  // });
+    }
+    return true
+  });
+
 }
 
 const isHoveringTitle = ref(false)

+ 1 - 1
src/entrypoints/sidepanel/component/tools.vue

@@ -20,7 +20,7 @@ const emit = defineEmits(['readClick', 'uploadFile', 'handleCapture', 'addNewDia
       </el-tooltip>
       <span class="separator"></span>
       <el-upload style="display:inline-block" :before-upload="(file: any) => emit('uploadFile', file)" :multiple="false"
-        name="file" :show-file-list="false" :accept="'.xlsx'">
+        name="file" :show-file-list="false" :accept="'.xlsx,.pdf,.doc,.docx'">
         <el-tooltip effect="dark" content="文件上传" placement="top">
           <el-button style="font-size:14px" :icon="Paperclip" circle />
         </el-tooltip>

+ 76 - 22
src/entrypoints/sidepanel/hook/useMsg.ts

@@ -2,6 +2,8 @@
 import {ref, reactive, nextTick, inject} from 'vue';
 import avator from '@/public/icon/32.png';
 import moment from 'moment'
+// import { getFileContent, getFormKey, buildObjPrompt } from '../../../utils/ai-service'
+import { ElMessage } from 'element-plus';
 
 // import { sendMessage } from '@/utils/ai-service';
 export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Function) {
@@ -17,6 +19,47 @@ 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
+        })
+
+        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)
+            console.log({
+                body: form,
+                input_data: res.data
+            });
+
+            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)
+        } catch (error) {
+            obj.content = '解析出错'
+        } finally {
+
+        }
+    }
+
     // 发送消息
     const addMessage = (msg: any, fetch: any) => {
         if (!msg) return
@@ -57,19 +100,32 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
 
     const sendRequese = async (msg: any, addHtml = false) => {
         const res: any = await getPageInfo()
-        if (type.value === '2' && msg.startsWith('/')) {
+
+
+        if ((type.value === '2' && msg.startsWith('/')) || msg.startsWith('请')) {
+            if (!taklToHtml.value) return messages.value.push({
+                id:messages.value.length + 1,
+                username: '用户1',
+                content: '请打开与页面对话!',
+                rawContent: '请打开与页面对话!',
+                timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+                isSelf: false,
+                avatar: avator,
+                addToHistory: false
+            })
             indexTemp.value = 0
-            await fetchRes(msg)
-        } else {
+            fetchRes(msg)
+        }
+        else {
             if (!addHtml) msg = getSummaryPrompt(res.content)
-            await streamRes(msg, addHtml)
+            streamRes(msg, addHtml)
         }
     }
 
     const fetchRes = async (msg: any) => {
         sendLoading.value = true
         const obj: any = reactive({
-            id: moment(),
+            id: messages.value.length + 1,
             username: '用户1',
             content: '',
             timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
@@ -78,11 +134,9 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
             addToHistory: !taklToHtml.value
         })
         messages.value.push(obj)
-        scrollbar.value?.setScrollTop(99999);
-        if (type.value === '2') {
-            fetchDataAndProcess && await fetchDataAndProcess(msg, obj)
-            sendLoading.value = false
-        }
+        nextTick(() => scrollbar.value?.setScrollTop(99999))
+        await fetchDataAndProcess(msg, obj)
+        sendLoading.value = false
     }
 
     const streamRes = async (msg: any, addHtml: any) => {
@@ -144,29 +198,28 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
         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 = () => {
-        const arr = xlsxData.value;
-        chrome.runtime.sendMessage({
-            type: 'FROM_SIDE_PANEL_TO_INPUT_FORM',
-            data: {
-                excelData: arr,
-                formData: formMap.value
-            }
-        });
-    }
+  const handleInput = () => {
+    chrome.runtime.sendMessage({
+      type: 'FROM_SIDE_PANEL_TO_INPUT_FORM',
+      data: {
+        excelData: xlsxData.value,
+        formData: formMap.value
+      }
+    });
+  }
 
     return {
         msgUuid,
@@ -182,6 +235,7 @@ export function useMsg(scrollbar?: any, xlsxData?: any, fetchDataAndProcess?: Fu
         sendRequese,
         getPageInfo,
         streamRes,
-        handleInput
+        handleInput,
+        getFileValue
     }
 }

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

@@ -7,4 +7,4 @@ export function useSummary(addMessage: Function, sendRequese: Function) {
   return {
     handleCardButtonClick
   }
-}
+}

+ 1 - 0
src/entrypoints/sidepanel/main.ts

@@ -11,4 +11,5 @@ const app = createApp(App).use(ElementPlus, {locale: locale, size: 'small'});
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
     app.component(key, component)
 }
+
 app.mount('#app')

+ 9 - 27
src/entrypoints/sidepanel/mock.ts

@@ -25,33 +25,15 @@ export const options = [
 ];
 
 export const mockData = [
-    {
-        action: 'click',
-        class: "ant-menu-item",
-        tag: "li",
-        innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>",
-        id: "",
-        text: "项目建档",
-        next: "是"
-    },
-    {
-        action: 'click',
-        class: "ant-menu-item",
-        tag: "button",
-        innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>",
-        id: "",
-        text: "新增",
-        next: "是"
-    },
-    {
-        action: 'show',
-        class: "ant-menu-item",
-        tag: "button",
-        innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>",
-        id: "",
-        text: "请上传数据",
-        next: "是"
-    },
+  { action: 'click', class: "ant-menu-item", tag: "li", innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>", id: "", text: "项目建档", next: "是" },
+  { action: 'click', class: "ant-menu-item", tag: "button", innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>", id: "", text: "新增", next: "否" },
+  { action: 'show', class: "ant-menu-item", tag: "button", innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>", id: "", text: "请上传数据", next: "是" },
+]
+
+export const mockData2 = [
+  { action: 'click', class: "ant-menu-item", tag: "li", innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>", id: "", text: "我的简历", next: "是" },
+  { action: 'click', class: "ant-menu-item", tag: "button", innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>", id: "", text: "去录入", next: "否" },
+  { action: 'show', class: "ant-menu-item", tag: "button", innerHTML: "<span class=\"ant-menu-item-icon\"><span role=\"img\" aria-label=\"book\" class=\"anticon anticon-book\"></span></span><span class=\"ant-menu-title-content\"><span>项目建档</span></span>", id: "", text: "请上传数据", next: "是" },
 ]
 
 export const startMsg = {

+ 50 - 13
src/utils/ai-service.js

@@ -10,10 +10,29 @@ export const openai = new OpenAI(
         dangerouslyAllowBrowser: true,
     }
 )
-
+export async function getFileContent(data) {
+    try {
+        const res = await fetch('http://180.76.147.97:18899/upload_file', {
+            method: 'post',
+            body: data,
+        }).then(res => res.json())
+        return res
+    } catch (error) {
+    }
+}
+export async function getFormKey(data) {
+    try {
+        const res = await fetch('http://180.76.147.97:18899/uie', {
+            method: 'post',
+            body: JSON.stringify(data),
+        }).then(res => res.json())
+        return res
+    } catch (error) {
+    }
+}
 export async function hepl(data) {
     try {
-        const res = await fetch('http://192.168.1.188:18899/test', {
+        const res = await fetch(' http://180.76.147.97:18899/test', {
             method: 'post',
             body: JSON.stringify(data)
         }).then(res => res.json())
@@ -155,13 +174,13 @@ export function formatMessage(text) {
 }
 
 export function buildExcelUnderstandingPrompt(data, fileName, pageInfo) {
-    if (!data || data.length < 2) {
-        return "这是一个空的Excel文件,请检查文件内容。";
-    }
+    // if (!data || data.length < 2) {
+    //     return "这是一个空的Excel文件,请检查文件内容。";
+    // }
 
 
-    const headers = data[0];
-    const rows = data.slice(1);
+    // const headers = data[0];
+    // const rows = data.slice(1);
     // data[0].forEach((header, i) => {
     //     if (!this.excelData[header]) this.excelData[header] = []
     //     this.excelData[header].push(data[1][i])
@@ -170,19 +189,37 @@ export function buildExcelUnderstandingPrompt(data, fileName, pageInfo) {
     return `我将向你展示一个通过SheetJS库读取的Excel文件内容和一个form表单。请帮我理解这些数据:
 
 文件名:${fileName}
-列标题:${headers.join(", ")}
+列标题:${data.join(", ")}
 
 表单内容:
 ${pageInfo}
              
 要求:
-1. 请分析表单中实际可操作的表单项,
-2. 并根据实际可操作的表单项的所有信息与上传excel文件中的列标题进行匹配,生成表单项与excel文件中列标题的数组,并使用findBy告诉我通过表单项的什么字段信息匹配到的,使用findByValue告诉我匹配到的表单项字段值,使用excelColumn字段告诉我excel文件中列标题的值。在一个字段内返回
+1. 请根据表单中的表单项和列标题进行匹配,一定以表单为准!
+2. 生成表单项与列标题对应的数组,并使用findBy告诉我通过表单项的什么字段信息匹配到的,使用findByValue告诉我匹配到的表单项字段值,使用excelColumn字段告诉我excel文件中列标题的值。
+3. 根据label匹配,findBy是label,并通过findByValue给我label元素的值,根据id匹配,findBy是id,并通过findByValue给是id的值,
 3. 并去除没有匹配到的表单项和excel文件中没有匹配到的列,
 4. 通过type字段告诉我输入项的类型
-5. 如果表单项有label标签,同时返回label,通过label字段告诉我label元素的文本
-6. 优先根据id匹配,再根据placeholder匹配,再根据其他内容匹配
-7. 仅返回数组,不要返回任何其他内容。`
+5. 表单项有label,根据label匹配,没有label根据placeholder匹配,没有placeholder,根据id匹配,再根据其他内容匹配
+6. 仅返回数组,不要返回任何其他内容。`
+}
+// 5. 如果表单项有label标签,同时返回label, 通过label字段告诉我label元素的文本
+export function buildObjPrompt(obj,  pageInfo) {
+  
+
+    return `我将向你展示一个对象和一个form表单。请帮我理解这些数据:
+
+对象:${JSON.stringify(obj)}
+表单内容:
+${pageInfo}
+             
+要求:
+1. 请根据表单中的表单项和对象进行匹配,一定以表单为准!
+2. 表单项有label,根据label匹配,没有label根据placeholder匹配,没有placeholder,根据id匹配,再根据其他内容匹配
+3. 并根据实际可操作的表单项的所有信息与上传的对象的key进行匹配,生成表单项与key的数组,并使用findBy告诉我通过表单项的什么字段信息匹配到的,使用findByValue告诉我匹配到的表单项字段值,使用excelColumn字段告诉我对应的key值。在一个字段内返回
+4. 并去除没有匹配到的表单项和对象中没有匹配到的key,
+5. 通过type字段告诉我输入项的类型,如果对象中key对应的是日期,type统一返回date
+6. 仅返回数组,不要返回任何其他内容。`
 }
 function escapeHtml(html) {
     const div = document.createElement("div");

+ 57 - 57
src/utils/page-analyzer.js

@@ -8,14 +8,14 @@ export default class PageAnalyzer {
    * 分析页面内容
    * @returns {Object} 页面分析结果
    */
-  analyzePage(iframe = false) {
+  analyzePage(form = false) {
     try {
       // 检查Readability是否可用
       if (typeof Readability === "undefined") {
         console.warn(
           "Readability not loaded, falling back to basic extraction"
         );
-        return this.fallbackAnalysis(iframe);
+        return this.fallbackAnalysis(form);
       }
 
       // 创建文档副本以避免修改原始DOM
@@ -68,71 +68,20 @@ export default class PageAnalyzer {
       }
     } else {
       const content = document.body.cloneNode(true);
-      cleanPage(content)
+      return cleanPage(content)
       // .trim().replace(/\s+/g, " ")
       // content
       //     .querySelectorAll("script, style, iframe, nav, header, footer,svg")
       //     .forEach((el) => el.remove());
 
-      const regex = /\s+/g;
-
-      // 定义标准 HTML 属性集合 排除id class style href src target
-      const standardAttributes = new Set(['alt', 'title', 'type', 'value', 'name', 'placeholder', 'disabled', 'checked', 'selected', 'readonly', 'required', 'maxlength', 'min', 'max', 'step', 'pattern', 'autocomplete', 'autofocus', 'multiple', 'rows', 'cols', 'rel', 'aria-*']);
-
-      // 创建一个临时容器
-      const temp = document.createElement('div');
-      temp.innerHTML = content.outerHTML;
-      // 递归删除空标签
-      function removeEmpty(element) {
-        const children = Array.from(element.children);
-        children.forEach(child => {
-          removeEmpty(child); // 递归处理子元素
-        });
-
-        // 检查标签是否为空
-        if (!element.innerHTML.trim()) {
-          element.remove(); // 删除空标签
-        }
-      }
-
-      // 从临时容器的子元素开始处理
-      removeEmpty(temp);
-
-      // 删除 <link> 标签
-      const linkTags = temp.querySelectorAll('link');
-      linkTags.forEach(link => {
-        link.remove();
-      });
-
-      // 遍历所有元素
-      const elements = temp.querySelectorAll('*');
-      elements.forEach(element => {
-        // 获取所有属性
-        const attributes = Array.from(element.attributes);
-        attributes.forEach(attr => {
-          // 如果属性不是标准属性,则移除
-          if (!standardAttributes.has(attr.name) && !attr.name.startsWith('aria-')) {
-            element.removeAttribute(attr.name);
-          }
-        });
-      });
-
-      // 获取处理后的 HTML 字符串
-      const cleanedHtml = temp.innerHTML.trim().replace(regex, " ");
-
-      // 销毁临时容器
-      temp.remove();
-
-      console.log(cleanedHtml)
-      // content.outerHTML.trim().replace(/\s+/g, " ");
-      return cleanedHtml;
+      
     }
 
 
   }
 };
 
-function cleanPage(body) {
+export  function cleanPage(body) {
 
   // 移除所有行内样式
   const elementsWithInlineStyle = body.querySelectorAll('[style]');
@@ -167,7 +116,58 @@ function cleanPage(body) {
   const ads = body.querySelectorAll('.ad, .advertisement, .ads');
   ads.forEach(ad => ad.remove());
 
-  console.log('页面清理完成!');
+  const regex = /\s+/g;
+
+  // 定义标准 HTML 属性集合 排除id class style href src target
+  const standardAttributes = new Set(['alt', 'title', 'type', 'value', 'name', 'placeholder', 'disabled', 'checked', 'selected', 'readonly', 'required', 'maxlength', 'min', 'max', 'step', 'pattern', 'autocomplete', 'autofocus', 'multiple', 'rows', 'cols', 'rel', 'aria-*']);
+
+  // 创建一个临时容器
+  const temp = document.createElement('div');
+  temp.innerHTML = body.outerHTML;
+  // 递归删除空标签
+  function removeEmpty(element) {
+    const children = Array.from(element.children);
+    children.forEach(child => {
+      removeEmpty(child); // 递归处理子元素
+    });
+
+    // 检查标签是否为空
+    if (!element.innerHTML.trim()) {
+      element.remove(); // 删除空标签
+    }
+  }
+
+  // 从临时容器的子元素开始处理
+  removeEmpty(temp);
+
+  // 删除 <link> 标签
+  const linkTags = temp.querySelectorAll('link');
+  linkTags.forEach(link => {
+    link.remove();
+  });
+
+  // 遍历所有元素
+  const elements = temp.querySelectorAll('*');
+  elements.forEach(element => {
+    // 获取所有属性
+    const attributes = Array.from(element.attributes);
+    attributes.forEach(attr => {
+      // 如果属性不是标准属性,则移除
+      if (!standardAttributes.has(attr.name) && !attr.name.startsWith('aria-')) {
+        element.removeAttribute(attr.name);
+      }
+    });
+  });
+
+  // 获取处理后的 HTML 字符串
+  const cleanedHtml = temp.innerHTML.trim().replace(regex, " ");
+
+  // 销毁临时容器
+  temp.remove();
+
+  console.log(cleanedHtml)
+  // content.outerHTML.trim().replace(/\s+/g, " ");
+  return cleanedHtml;
 }
 
 

+ 1 - 1
wxt.config.ts

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