Explorar el Código

格式化代码,统一格式

wzg hace 5 meses
padre
commit
2c0afe47ea
Se han modificado 35 ficheros con 2087 adiciones y 2014 borrados
  1. 5 5
      postcss.config.js
  2. 4 4
      shims-vue.d.ts
  3. 6 1
      src/assets/vue.svg
  4. 109 109
      src/entrypoints/background.js
  5. 415 411
      src/entrypoints/content.js
  6. 39 35
      src/entrypoints/options/App.vue
  7. 18 18
      src/entrypoints/options/index.html
  8. 6 6
      src/entrypoints/options/main.ts
  9. 59 59
      src/entrypoints/options/style.css
  10. 29 29
      src/entrypoints/sidepanel/App.vue
  11. 131 131
      src/entrypoints/sidepanel/Chat.vue
  12. 82 82
      src/entrypoints/sidepanel/component/historyComponent.vue
  13. 33 33
      src/entrypoints/sidepanel/component/inputArea.vue
  14. 12 12
      src/entrypoints/sidepanel/component/tools.vue
  15. 198 198
      src/entrypoints/sidepanel/css/chat.scss
  16. 13 13
      src/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts
  17. 184 184
      src/entrypoints/sidepanel/hook/useIndexedDB.ts
  18. 135 135
      src/entrypoints/sidepanel/hook/useMsg.ts
  19. 10 10
      src/entrypoints/sidepanel/index.html
  20. 13 13
      src/entrypoints/sidepanel/main.ts
  21. 69 21
      src/entrypoints/sidepanel/mock.ts
  22. 40 40
      src/entrypoints/sidepanel/style.css
  23. 47 46
      src/entrypoints/sidepanel/utils/index.js
  24. 14 13
      src/public/wxt.svg
  25. 3 3
      src/store/index.ts
  26. 75 75
      src/store/modules/indexedDB.ts
  27. 11 11
      src/store/modules/msg.ts
  28. 168 159
      src/utils/ai-service.js
  29. 19 19
      src/utils/dynamicTime.js
  30. 57 56
      src/utils/page-analyzer.js
  31. 8 8
      src/utils/rem.js
  32. 52 52
      src/utils/request.js
  33. 2 2
      tailwind.config.js
  34. 2 2
      tsconfig.json
  35. 19 19
      wxt.config.ts

+ 5 - 5
postcss.config.js

@@ -1,6 +1,6 @@
 export default {
-    plugins: {
-        tailwindcss: {},
-        autoprefixer: {},
-    },
-};
+  plugins: {
+    tailwindcss: {},
+    autoprefixer: {}
+  }
+}

+ 4 - 4
shims-vue.d.ts

@@ -1,5 +1,5 @@
-declare module "*.vue" {
-  import { DefineComponent } from "vue";
-  const component: DefineComponent<{}, {}, any>;
-  export default component;
+declare module '*.vue' {
+  import { DefineComponent } from 'vue'
+  const component: DefineComponent<{}, {}, any>
+  export default component
 }

+ 6 - 1
src/assets/vue.svg

@@ -1 +1,6 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img"
+     class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198">
+    <path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path>
+    <path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path>
+    <path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path>
+</svg>

+ 109 - 109
src/entrypoints/background.js

@@ -1,117 +1,117 @@
 export default defineBackground(() => {
 
-    let currentTabId 
-    // Executed when background is loaded
-    chrome.sidePanel
-        .setPanelBehavior({ openPanelOnActionClick: true })
-        .catch((error) => console.error(error));
-    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
+  let currentTabId
+  // Executed when background is loaded
+  chrome.sidePanel
+    .setPanelBehavior({ openPanelOnActionClick: true })
+    .catch((error) => console.error(error))
+  chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
 
-        
-        if (message.type === 'PAGE_INFO') {
-            // 转发到侧边栏
-            chrome.runtime.sendMessage({
-                type: 'TO_SIDE_PANEL_PAGE_INFO',
-                data: message.data
-            });
-        }
-        
-        if (message.type === 'FROM_SIDE_PANEL_TO_ACTION') {
-            console.log(565888);
-            chrome.tabs.query({ active: true }, (tabs) => {
-                console.log(tabs);
-                
-                if (tabs.length === 0) return; // 确保有活动标签页
-                const tabId = tabs[0].id; // 获取当前活动的 tabId
-                chrome.tabs.sendMessage(tabId, { type: "GET_TAG_ACTION", data: message.data }, (response) => {
-                    if (chrome.runtime.lastError) {
-                        console.error("消息发送失败:", chrome.runtime.lastError.message);
-                    } else {
-                        console.log("收到 content script 响应:", response);
-                        console.log(response,998);
-                        
-                        sendResponse(response)
-                    }
-                    return true
-                });
-            });
-            return true
-        } 
-        if (message.type === 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM') {
-            chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
-                if (tabs.length === 0) return; // 确保有活动标签页
-                const tabId = tabs[0].id; // 获取当前活动的 tabId
-                chrome.tabs.sendMessage(tabId, { type: "GET_PAGE_FORM", data: "Hello from background!" }, (response) => {
-                    if (chrome.runtime.lastError) {
-                        console.error("消息发送失败:", chrome.runtime.lastError.message);
-                    } else {
-                        console.log("收到 content script 响应:", response);
-                        sendResponse(response)
-                    }
 
-                });
-            });
-            return true
-        } 
-        if (message.type === 'FROM_SIDE_PANEL_TO_INPUT_FORM') {
-            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) => {
-                    if (chrome.runtime.lastError) {
-                        console.error("消息发送失败:", chrome.runtime.lastError.message);
-                    } else {
-                        console.log("收到 content script 响应:", response);
-                        sendResponse(response.data)
-                    }
+    if (message.type === 'PAGE_INFO') {
+      // 转发到侧边栏
+      chrome.runtime.sendMessage({
+        type: 'TO_SIDE_PANEL_PAGE_INFO',
+        data: message.data
+      })
+    }
 
-                });
-            });
-            return true
-        }
-        if (message.type === 'FROM_SIDE_PANEL_TO_GET_PAGE_INFO') {
-            chrome.tabs.query({ active: true }, (tabs) => {
-                if (tabs.length === 0) return; // 确保有活动标签页
-                const tabId = tabs[0].id; // 获取当前活动的 tabId
-                chrome.tabs.sendMessage(tabId, { type: "GET_PAGE_INFO", data: "Hello from background!" }, (response) => {
-                    if (chrome.runtime.lastError) {
-                        console.error("消息发送失败:", chrome.runtime.lastError.message);
-                    } else {
-                        console.log(response,777);
-                        
-                        console.log("收到 content script 响应:", response);
-                        sendResponse(response.data)
-                    }
-                   
-                });
-            });
-            return true
-        }
-    });
-    chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
-        if (changeInfo.status === "complete" && tab.url) {
-            chrome.runtime.sendMessage({
-                type: 'TO_SIDE_PANEL_PAGE_CHANGE',
-                data: tab
-            });
-            currentTabId = tab.id
-        }
-    });
-    chrome.tabs.onActivated.addListener((activeInfo) => {
-        chrome.tabs.get(activeInfo.tabId, (tab) => {
-            if (chrome.runtime.lastError) {
-                console.error(chrome.runtime.lastError);
-                return;
-            }
-            chrome.runtime.sendMessage({
-                type: 'TO_SIDE_PANEL_PAGE_CHANGE',
-                data: tab
-            });
-            console.log("用户切换到新 Tab,URL:", tab);
-            currentTabId = tab.id
-        });
-    });
+    if (message.type === 'FROM_SIDE_PANEL_TO_ACTION') {
+      console.log(565888)
+      chrome.tabs.query({ active: true }, (tabs) => {
+        console.log(tabs)
 
-});
+        if (tabs.length === 0) return // 确保有活动标签页
+        const tabId = tabs[0].id // 获取当前活动的 tabId
+        chrome.tabs.sendMessage(tabId, { type: 'GET_TAG_ACTION', data: message.data }, (response) => {
+          if (chrome.runtime.lastError) {
+            console.error('消息发送失败:', chrome.runtime.lastError.message)
+          } else {
+            console.log('收到 content script 响应:', response)
+            console.log(response, 998)
+
+            sendResponse(response)
+          }
+          return true
+        })
+      })
+      return true
+    }
+    if (message.type === 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM') {
+      chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
+        if (tabs.length === 0) return // 确保有活动标签页
+        const tabId = tabs[0].id // 获取当前活动的 tabId
+        chrome.tabs.sendMessage(tabId, { type: 'GET_PAGE_FORM', data: 'Hello from background!' }, (response) => {
+          if (chrome.runtime.lastError) {
+            console.error('消息发送失败:', chrome.runtime.lastError.message)
+          } else {
+            console.log('收到 content script 响应:', response)
+            sendResponse(response)
+          }
+
+        })
+      })
+      return true
+    }
+    if (message.type === 'FROM_SIDE_PANEL_TO_INPUT_FORM') {
+      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) => {
+          if (chrome.runtime.lastError) {
+            console.error('消息发送失败:', chrome.runtime.lastError.message)
+          } else {
+            console.log('收到 content script 响应:', response)
+            sendResponse(response.data)
+          }
+
+        })
+      })
+      return true
+    }
+    if (message.type === 'FROM_SIDE_PANEL_TO_GET_PAGE_INFO') {
+      chrome.tabs.query({ active: true }, (tabs) => {
+        if (tabs.length === 0) return // 确保有活动标签页
+        const tabId = tabs[0].id // 获取当前活动的 tabId
+        chrome.tabs.sendMessage(tabId, { type: 'GET_PAGE_INFO', data: 'Hello from background!' }, (response) => {
+          if (chrome.runtime.lastError) {
+            console.error('消息发送失败:', chrome.runtime.lastError.message)
+          } else {
+            console.log(response, 777)
+
+            console.log('收到 content script 响应:', response)
+            sendResponse(response.data)
+          }
+
+        })
+      })
+      return true
+    }
+  })
+  chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
+    if (changeInfo.status === 'complete' && tab.url) {
+      chrome.runtime.sendMessage({
+        type: 'TO_SIDE_PANEL_PAGE_CHANGE',
+        data: tab
+      })
+      currentTabId = tab.id
+    }
+  })
+  chrome.tabs.onActivated.addListener((activeInfo) => {
+    chrome.tabs.get(activeInfo.tabId, (tab) => {
+      if (chrome.runtime.lastError) {
+        console.error(chrome.runtime.lastError)
+        return
+      }
+      chrome.runtime.sendMessage({
+        type: 'TO_SIDE_PANEL_PAGE_CHANGE',
+        data: tab
+      })
+      console.log('用户切换到新 Tab,URL:', tab)
+      currentTabId = tab.id
+    })
+  })
+
+})
 
 // Allows users to open the side panel by clicking on the action toolbar icon

+ 415 - 411
src/entrypoints/content.js

@@ -2,437 +2,441 @@
 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())
-            console.log(document.title);
+  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)
+
+    }
+    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 (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 (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]
         }
-        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 (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
+        // 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 (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])
+                  }
                 }
-                // 添加红色边框,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 (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 (message.type === 'GET_PAGE_FORM') {
+          if (item.type === 'date') {
 
-                const len = document.querySelectorAll("form").length
-                if (document.title === '智能招采' && len === 1) {
-                    sendResponse({
-                        status: 'error',
-                        message: '没有找到表单'
-                    })
-                    return
-                }
+            const input = formChildren.find(child => child.id === item.findByValue)
+            if (excelDataA[item.excelColumn]) {
 
-                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()
-                },
+              await simulateCompleteUserAction(input, input, formatDate(excelDataA[item.excelColumn]), formatDate(excelDataA[item.excelColumn]))
             }
+          }
         }
-        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`;
+        if (item.findBy === 'placeholder') {
+          const input = formChildren.find(child => child.placeholder === item.findByValue)
+          if (input) {
+            simulateUserInput(input, excelDataA[item.excelColumn])
+          }
         }
-        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.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' || item.type === 'textarea') {
-                        let input
-                        if (item.type === 'textarea') {
-                             input = findLabelForTextarea(label)
-                        } else input = findLabelForInput(label)
-                        if (input) {
-                            if (input.value) continue
-                            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])
-                        }
-                    }
-                }
-            }
-        }
-        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);
+          if (item.type === 'date') {
+            const input = findLabelForInput(label)
+            console.log(input, excelDataA[item.excelColumn])
 
-            // 可选:如果表单使用了 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 < 5; i++) {
-                const input = p.getElementsByTagName('input')
-                if (input.length > 0) {
-                    return input[0]
-                }
-                p = p.parentElement
+            if (input) {
+              await simulateCompleteUserAction(input, input, formatDate(excelDataA[item.excelColumn]), formatDate(excelDataA[item.excelColumn]))
             }
-            return null
-        }
-        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
+          }
+
+          if (item.type === 'input' || item.type === 'text' || item.type === 'number' || item.type === 'tel' || item.type === 'email' || item.type === 'textarea') {
+            let input
+            if (item.type === 'textarea') {
+              input = findLabelForTextarea(label)
+            } else input = findLabelForInput(label)
+            if (input) {
+              if (input.value) continue
+              console.log(excelDataA[item.excelColumn])
+
+              await simulateUserInput(input, excelDataA[item.excelColumn])
             }
-            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]
-                }
-                p = p.parentElement
+          }
+          if (item.type === 'select') {
+            const input = findLabelForInput(label)
+            if (input) {
+              await simulateUserInput(input, excelDataA[item.excelColumn])
             }
-            return null
+          }
         }
-        const findLabelForTextarea = (label) => {
-            let p = label.parentElement
-            for (let i = 0; i < 10; i++) {
-                const span = p.getElementsByTagName('textarea')
-                if (span.length > 0) {
-                    return [...span]
-                }
-                p = p.parentElement
-            }
-            return null
+      }
+    }
+    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 < 5; i++) {
+        const input = p.getElementsByTagName('input')
+        if (input.length > 0) {
+          return input[0]
+        }
+        p = p.parentElement
+      }
+      return null
+    }
+    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
+    }
+    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 findLabelForTextarea = (label) => {
+      let p = label.parentElement
+      for (let i = 0; i < 10; i++) {
+        const span = p.getElementsByTagName('textarea')
+        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)
         }
-        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);
-                }
 
-                // 触发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);
+        // 触发change事件
+        element.dispatchEvent(new Event('change', { bubbles: true }))
+      }
 
-            // 获取年、月、日
-            const year = d.getFullYear();
-            const month = String(d.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要加1
-            const day = String(d.getDate()).padStart(2, '0');
+      // 3. 查找td元素
+      const findTdByTitle = (title, timeout = 5000) => {
+        return new Promise((resolve, reject) => {
+          const startTime = Date.now()
 
-            return `${year}-${month}-${day}`;
-        }
+          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)
+
+      // 获取年、月、日
+      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}`
+    }
+
+  }
+})

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 39 - 35
src/entrypoints/options/App.vue


+ 18 - 18
src/entrypoints/options/index.html

@@ -1,21 +1,21 @@
 <!doctype html>
 <html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Default Popup Title</title>
-    <meta name="manifest.type" content="browser_action" />
-  </head>
-  <body>
-    <div id="app"></div>
-    <script>
-      let timer = null
-         chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
-            // The callback for runtime.onMessage must return falsy if we're not sending a response
-            if (message.type === 'updateSidePanel') sendResponse(111)
-            return
-          });
-    </script>
-    <script type="module" src="./main.ts"></script>
-  </body>
+<head>
+  <meta charset="UTF-8" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <title>Default Popup Title</title>
+  <meta name="manifest.type" content="browser_action" />
+</head>
+<body>
+<div id="app"></div>
+<script>
+  let timer = null
+  chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
+    // The callback for runtime.onMessage must return falsy if we're not sending a response
+    if (message.type === 'updateSidePanel') sendResponse(111)
+    return
+  })
+</script>
+<script type="module" src="./main.ts"></script>
+</body>
 </html>

+ 6 - 6
src/entrypoints/options/main.ts

@@ -1,14 +1,14 @@
-import { createApp } from 'vue';
-import './style.css';
-import App from './App.vue';
+import { createApp } from 'vue'
+import './style.css'
+import App from './App.vue'
 import '@/../node_modules/element-plus/dist/index.css'
 import ElementPlus from 'element-plus'
 import 'element-plus/dist/index.css'
-import locale from 'element-plus/es/locale/lang/zh-cn'; // 中文语言
+import locale from 'element-plus/es/locale/lang/zh-cn' // 中文语言
 import * as ElementPlusIconsVue from '@element-plus/icons-vue'
 
-const app = createApp(App).use(ElementPlus, { locale: locale });
+const app = createApp(App).use(ElementPlus, { locale: locale })
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
-    app.component(key, component)
+  app.component(key, component)
 }
 app.mount('#app')

+ 59 - 59
src/entrypoints/options/style.css

@@ -1,101 +1,101 @@
 :root {
-  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
-  line-height: 1.5;
-  font-weight: 400;
-
-  color-scheme: light dark;
-  color: rgba(255, 255, 255, 0.87);
-  background-color: #242424;
-
-  font-synthesis: none;
-  text-rendering: optimizeLegibility;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  -webkit-text-size-adjust: 100%;
+    font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+    line-height: 1.5;
+    font-weight: 400;
+
+    color-scheme: light dark;
+    color: rgba(255, 255, 255, 0.87);
+    background-color: #242424;
+
+    font-synthesis: none;
+    text-rendering: optimizeLegibility;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    -webkit-text-size-adjust: 100%;
 }
 
 * {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
 }
 
 a {
-  font-weight: 500;
-  color: #646cff;
-  text-decoration: inherit;
+    font-weight: 500;
+    color: #646cff;
+    text-decoration: inherit;
 }
 
 a:hover {
-  color: #535bf2;
+    color: #535bf2;
 }
 
 a {
-  font-weight: 500;
-  color: #646cff;
-  text-decoration: inherit;
+    font-weight: 500;
+    color: #646cff;
+    text-decoration: inherit;
 }
 
 a:hover {
-  color: #535bf2;
+    color: #535bf2;
 }
 
 body {
-  margin: 0;
-  display: flex;
-  place-items: center;
-  min-width: 320px;
-  min-height: 100vh;
+    margin: 0;
+    display: flex;
+    place-items: center;
+    min-width: 320px;
+    min-height: 100vh;
 }
 
 h1 {
-  font-size: 3.2em;
-  line-height: 1.1;
+    font-size: 3.2em;
+    line-height: 1.1;
 }
 
 button {
-  border-radius: 8px;
-  border: 1px solid transparent;
-  padding: 0.6em 1.2em;
-  font-size: 1em;
-  font-weight: 500;
-  font-family: inherit;
-  background-color: #1a1a1a;
-  cursor: pointer;
-  transition: border-color 0.25s;
+    border-radius: 8px;
+    border: 1px solid transparent;
+    padding: 0.6em 1.2em;
+    font-size: 1em;
+    font-weight: 500;
+    font-family: inherit;
+    background-color: #1a1a1a;
+    cursor: pointer;
+    transition: border-color 0.25s;
 }
 
 button:hover {
-  border-color: #646cff;
+    border-color: #646cff;
 }
 
 button:focus,
 button:focus-visible {
-  outline: 4px auto -webkit-focus-ring-color;
+    outline: 4px auto -webkit-focus-ring-color;
 }
 
 .card {
-  padding: 2em;
+    padding: 2em;
 }
 
 #app {
-  margin: auto;
-  max-width: 1280px;
-  width: 100%;
-  height: 100vh;
+    margin: auto;
+    max-width: 1280px;
+    width: 100%;
+    height: 100vh;
 }
 
 @media (prefers-color-scheme: light) {
-  :root {
-    color: #213547;
-    background-color: #ffffff;
-  }
-
-  a:hover {
-    color: #747bff;
-  }
-
-  button {
-    background-color: #f9f9f9;
-  }
+    :root {
+        color: #213547;
+        background-color: #ffffff;
+    }
+
+    a:hover {
+        color: #747bff;
+    }
+
+    button {
+        background-color: #f9f9f9;
+    }
 }

+ 29 - 29
src/entrypoints/sidepanel/App.vue

@@ -8,35 +8,35 @@
   <!--    </a>-->
   <!--  </div>-->
   <!--  <HelloWorld msg="WXT + Vue" />-->
-  <Chat/>
+  <Chat />
   <!-- <div @click="() => openFile()">按钮</div> -->
 
 </template>
 
 <script lang="ts" setup>
-import {provide} from 'vue';
-import Chat from '@/entrypoints/sidepanel/Chat.vue';
+import { provide } from 'vue'
+import Chat from '@/entrypoints/sidepanel/Chat.vue'
 import axios from '@/utils/request'
-import {onBeforeUnmount, onMounted} from 'vue';
-import {useIndexedDB} from "@/entrypoints/sidepanel/hook/useIndexedDB";
+import { onBeforeUnmount, onMounted } from 'vue'
+import { useIndexedDB } from '@/entrypoints/sidepanel/hook/useIndexedDB'
 
-const {openDB, ...args} = useIndexedDB({
+const { openDB, ...args } = useIndexedDB({
   dbName: 'chatDB',
   version: localStorage.getItem('dbVersion') ? Number(localStorage.getItem('dbVersion')) : 1
 })
 
 // 提供实例给子组件
-provide('indexedDBHook', args);
+provide('indexedDBHook', args)
 
 
 async function openFile() {
   try {
-    const [fileHandle] = await window.showOpenFilePicker();
-    const file = await fileHandle.getFile();
-    const contents = await file.text();
-    console.log(file);
+    const [fileHandle] = await window.showOpenFilePicker()
+    const file = await fileHandle.getFile()
+    const contents = await file.text()
+    console.log(file)
   } catch (err) {
-    console.error('Error accessing file:', err);
+    console.error('Error accessing file:', err)
   }
 }
 
@@ -55,39 +55,39 @@ async function saveFile() {
       types: [
         {
           description: 'Text Files',
-          accept: {'text/plain': ['.txt']},
-        },
-      ],
-    };
-    const handle = await window.showSaveFilePicker(options);
-    const writable = await handle.createWritable();
-    await writable.write('Hello, World!');
-    await writable.close();
-    console.log('File saved successfully!');
+          accept: { 'text/plain': ['.txt'] }
+        }
+      ]
+    }
+    const handle = await window.showSaveFilePicker(options)
+    const writable = await handle.createWritable()
+    await writable.write('Hello, World!')
+    await writable.close()
+    console.log('File saved successfully!')
   } catch (err) {
-    console.error('Error saving file:', err);
+    console.error('Error saving file:', err)
   }
 }
 
 async function openDirectory() {
   try {
     // 显示文件夹选择对话框
-    const directoryHandle = await window.showDirectoryPicker();
-    console.log(`Selected directory: ${directoryHandle.name}`);
+    const directoryHandle = await window.showDirectoryPicker()
+    console.log(`Selected directory: ${directoryHandle.name}`)
 
     // 读取文件夹内容
     for await (const [name, handle] of directoryHandle.entries()) {
       if (handle.kind === 'file') {
-        console.log(`File: ${name}`);
+        console.log(`File: ${name}`)
         // 读取文件内容(可选)
-        const file = await handle.getFile();
-        console.log(`File content: ${await file.text()}`);
+        const file = await handle.getFile()
+        console.log(`File content: ${await file.text()}`)
       } else if (handle.kind === 'directory') {
-        console.log(`Sub-directory: ${name}`);
+        console.log(`Sub-directory: ${name}`)
       }
     }
   } catch (err) {
-    console.error('Error accessing directory:', err);
+    console.error('Error accessing directory:', err)
   }
 }
 

+ 131 - 131
src/entrypoints/sidepanel/Chat.vue

@@ -87,35 +87,35 @@
 </template>
 
 <script setup>
-import { ref, onMounted, nextTick, inject, useTemplateRef } from "vue";
-import { ElScrollbar, ElAvatar, ElInput, ElButton } from "element-plus";
-import moment from "moment";
+import { ref, onMounted, nextTick, inject, useTemplateRef } from 'vue'
+import { ElScrollbar, ElAvatar, ElInput, ElButton } from 'element-plus'
+import moment from 'moment'
 import {
   buildExcelUnderstandingPrompt,
   getFileSummaryPrompt,
   getSummaryPrompt,
   getFileContent,
   buildObjPrompt
-} from "@/utils/ai-service.js";
-import { storeToRefs } from "pinia";
-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 { mockData, startMsg, mockData2 } from "@/entrypoints/sidepanel/mock";
-import { useAutoResizeTextarea } from "@/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts";
-import { getPageInfo, getXlsxValue, handleInput } from "./utils/index.js";
-import { useMsgStore } from "@/store/modules/msg.ts";
+} from '@/utils/ai-service.js'
+import { storeToRefs } from 'pinia'
+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 { mockData, startMsg, mockData2 } from '@/entrypoints/sidepanel/mock'
+import { useAutoResizeTextarea } from '@/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts'
+import { getPageInfo, getXlsxValue, handleInput } from './utils/index.js'
+import { useMsgStore } from '@/store/modules/msg.ts'
 
 // 滚动条引用
-const scrollbar = ref(null);
-const xlsxData = ref({});
-const isShowPage = ref(false);
-const tareRef = useTemplateRef("textareaRef");
-const drawerRef = useTemplateRef("historyComponentRef");
+const scrollbar = ref(null)
+const xlsxData = ref({})
+const isShowPage = ref(false)
+const tareRef = useTemplateRef('textareaRef')
+const drawerRef = useTemplateRef('historyComponentRef')
 // 获取父组件提供的 Hook 实例
-const { registerStore, useStore } = inject("indexedDBHook");
-const { pageInfoList, messages, msgUuid } = storeToRefs(useMsgStore());
+const { registerStore, useStore } = inject('indexedDBHook')
+const { pageInfoList, messages, msgUuid } = storeToRefs(useMsgStore())
 const {
   taklToHtml,
   sendLoading,
@@ -123,206 +123,206 @@ const {
   streamRes,
   getFormKeyAndValue,
   handleSend
-} = useMsg(scrollbar);
-const inputMessage = ref("");
-const pageInfo = ref("");
+} = useMsg(scrollbar)
+const inputMessage = ref('')
+const pageInfo = ref('')
 
 const addMessage = (msg, raw) => {
-  if (!msg) return;
+  if (!msg) return
   const newMessage = reactive({
     id: messages.value.length + 1,
-    username: "我",
+    username: '我',
     rawContent: raw ?? msg,
     content: msg,
-    timestamp: moment().format("YYYY-MM-DD HH:mm:ss"),
+    timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
     isSelf: true,
-    avatar: "https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png",
+    avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
     addToHistory: !taklToHtml.value
-  });
-  messages.value.push(newMessage);
-  useStore(msgUuid.value).add(newMessage);
+  })
+  messages.value.push(newMessage)
+  useStore(msgUuid.value).add(newMessage)
   nextTick(() => {
-    scrollbar.value?.setScrollTop(99999);
-  });
-  return newMessage;
-};
+    scrollbar.value?.setScrollTop(99999)
+  })
+  return newMessage
+}
 const handleSummary = async () => {
-  const res = await getPageInfo();
-  addMessage("总结页面", getSummaryPrompt(res.content));
-  handleSend();
-};
+  const res = await getPageInfo()
+  addMessage('总结页面', getSummaryPrompt(res.content))
+  handleSend()
+}
 
 function handelIntelligentFillingClick() {
-  inputMessage.value = "/智能填表 ";
-  type.value = "2";
+  inputMessage.value = '/智能填表 '
+  type.value = '2'
 }
 
 function handleCurrentData(e) {
-  drawerRef.value.drawer = false;
+  drawerRef.value.drawer = false
   if (!e) {
-    addNewDialogue();
-    return;
+    addNewDialogue()
+    return
   }
   // 添加indexDB Store配置
-  msgUuid.value = e;
+  msgUuid.value = e
   useStore(e).getAll().then((res) => {
-    messages.value = res;
+    messages.value = res
     nextTick(() => {
-      scrollbar.value?.setScrollTop(99999);
-    });
-  });
+      scrollbar.value?.setScrollTop(99999)
+    })
+  })
 }
 
 async function readClick() {
-  isShowPage.value = true;
-  taklToHtml.value = true;
-  const tempPageInfo = await getPageInfo();
-  pageInfo.value = tempPageInfo;
-  pageInfoList.value.push(tempPageInfo);
+  isShowPage.value = true
+  taklToHtml.value = true
+  const tempPageInfo = await getPageInfo()
+  pageInfo.value = tempPageInfo
+  pageInfoList.value.push(tempPageInfo)
 }
 
 function deletePageInfo(i) {
-  pageInfoList.value.splice(i, 1);
+  pageInfoList.value.splice(i, 1)
   if (pageInfoList.value.length === 0) {
-    isShowPage.value = false;
-    taklToHtml.value = false;
+    isShowPage.value = false
+    taklToHtml.value = false
   }
 
 }
 
 function addNewDialogue() {
-  messages.value = [];
-  msgUuid.value = "D" + Date.now().toString();
+  messages.value = []
+  msgUuid.value = 'D' + Date.now().toString()
   registerStore({
     name: msgUuid.value,
-    keyPath: "id"
-  });
-  messages.value.push(startMsg);
-  useStore(msgUuid.value).add(startMsg);
+    keyPath: 'id'
+  })
+  messages.value.push(startMsg)
+  useStore(msgUuid.value).add(startMsg)
 }
 
 async function handleAsk() {
-  if (sendLoading.value) return;
-  addMessage(inputMessage.value.trim());
-  handleSend(inputMessage.value.trim());
-  inputMessage.value = "";
+  if (sendLoading.value) return
+  addMessage(inputMessage.value.trim())
+  handleSend(inputMessage.value.trim())
+  inputMessage.value = ''
   // streamRes(taklToHtml)
 }
 
 function handleCapture() {
   ElMessage({
-    message: "开发中...",
+    message: '开发中...',
     grouping: true,
     showClose: true
-  });
+  })
 }
 
 function hisRecords() {
-  drawerRef.value.drawer = true;
+  drawerRef.value.drawer = true
 }
 
 const handleUpload = async (file) => {
-  if (type.value === "2") {
+  if (type.value === '2') {
     chrome.runtime.sendMessage({
-      type: "FROM_SIDE_PANEL_TO_GET_PAGE_FORM"
+      type: 'FROM_SIDE_PANEL_TO_GET_PAGE_FORM'
     }, async (response) => {
       if (chrome.runtime.lastError) {
-        console.error("消息发送错误:", chrome.runtime.lastError);
+        console.error('消息发送错误:', chrome.runtime.lastError)
       } else {
-        const fileExtension = file.name.split(".").pop().toLowerCase();
-        if (response.status === "error") return ElMessage({
+        const fileExtension = file.name.split('.').pop().toLowerCase()
+        if (response.status === 'error') return ElMessage({
           message: response.message,
-          type: "error",
+          type: 'error',
           duration: 4 * 1000,
           grouping: true
-        });
-        if (fileExtension === "xlsx") {
-          const readData = await getXlsxValue(file);
+        })
+        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));
-          const a = await streamRes();
-          handleInput(xlsxData.value, JSON.parse(a.split("json")[1].split("```")[0]));
+            xlsxData.value[header] = readData[1][i]
+          })
+          addMessage(`已上传文件:${file.name}`, buildExcelUnderstandingPrompt(readData[0], file?.name, response.data))
+          const a = await streamRes()
+          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);
-          xlsxData.value = res2.data;
-          msg.rawContent = buildObjPrompt(res2.data, response.data);
-          console.log();
+          const { data, msg } = await getFileValue(file)
+          const res2 = await getFormKeyAndValue(data, response.data)
+          xlsxData.value = res2.data
+          msg.rawContent = buildObjPrompt(res2.data, response.data)
+          console.log()
 
-          const a = await streamRes();
-          handleInput(xlsxData.value, JSON.parse(a.split("json")[1].split("```")[0]));
-          console.log(xlsxData.value);
-          console.log(type.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;
-    });
+      return true
+    })
   }
-  if (type.value === "") {
-    const fileVaue = await getFileValue(file);
+  if (type.value === '') {
+    const fileVaue = await getFileValue(file)
     // streamRes()
   }
-};
-let str = "";
+}
+let str = ''
 
 async function 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 = res.data;
+  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 = res.data
   return {
     data: res.data,
     msg
-  };
+  }
 }
 }
-const isHoveringTitle = ref(false);
+const isHoveringTitle = ref(false)
 // 组件挂载时滚动到底部
 onMounted(() => {
-  useAutoResizeTextarea(tareRef, inputMessage);
+  useAutoResizeTextarea(tareRef, inputMessage)
   chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
-    if (message.type === "TO_SIDE_PANEL_PAGE_INFO") {
-      pageInfo.value = message.data;
+    if (message.type === 'TO_SIDE_PANEL_PAGE_INFO') {
+      pageInfo.value = message.data
       // 转发到 content.js
       chrome.tabs.sendMessage(sender.tab.id, {
-        type: "TO_CONTENT_SCRIPT",
+        type: 'TO_CONTENT_SCRIPT',
         data: message.data
-      });
+      })
     }
-    if (message.type === "TO_SIDE_PANEL_PAGE_CHANGE") {
-      pageInfo.value = message.data;
+    if (message.type === 'TO_SIDE_PANEL_PAGE_CHANGE') {
+      pageInfo.value = message.data
     }
-  });
+  })
 
   // 添加标题悬停事件监听
   nextTick(() => {
-    const titleWrapper = document.querySelector(".title-wrapper");
+    const titleWrapper = document.querySelector('.title-wrapper')
     if (titleWrapper) {
-      titleWrapper.addEventListener("mouseenter", () => {
-        isHoveringTitle.value = true;
-      });
-      titleWrapper.addEventListener("mouseleave", () => {
-        isHoveringTitle.value = false;
-      });
+      titleWrapper.addEventListener('mouseenter', () => {
+        isHoveringTitle.value = true
+      })
+      titleWrapper.addEventListener('mouseleave', () => {
+        isHoveringTitle.value = false
+      })
     }
-    scrollbar.value?.setScrollTop(99999);
-  });
+    scrollbar.value?.setScrollTop(99999)
+  })
   // 添加indexDB Store配置
-  msgUuid.value = "D" + Date.now().toString();
+  msgUuid.value = 'D' + Date.now().toString()
   registerStore({
     name: msgUuid.value,
-    keyPath: "id"
-  });
-  messages.value.push(startMsg);
-  useStore(msgUuid.value).add(startMsg);
-});
+    keyPath: 'id'
+  })
+  messages.value.push(startMsg)
+  useStore(msgUuid.value).add(startMsg)
+})
 </script>
 
 <style lang="scss" scoped>

+ 82 - 82
src/entrypoints/sidepanel/component/historyComponent.vue

@@ -1,16 +1,16 @@
 <script setup lang="ts">
-import {ref, inject} from 'vue';
-import {Search, Delete, Paperclip} from "@element-plus/icons-vue";
-import {ElMessageBox,ElMessage} from "element-plus";
-
-const drawer = ref(false);
-const count = ref(0);
-const input = ref('');
-const loading = ref(false);
-const dataList = ref<any[]>([]);
+import { ref, inject } from 'vue'
+import { Search, Delete, Paperclip } from '@element-plus/icons-vue'
+import { ElMessageBox, ElMessage } from 'element-plus'
+
+const drawer = ref(false)
+const count = ref(0)
+const input = ref('')
+const loading = ref(false)
+const dataList = ref<any[]>([])
 // 获取父组件提供的 Hook 实例
-const {db, useStore, deleteDB} = inject('indexedDBHook') as any;
-const emit = defineEmits(['currentData']);
+const { db, useStore, deleteDB } = inject('indexedDBHook') as any
+const emit = defineEmits(['currentData'])
 
 const props = defineProps({
   msgUuid: {
@@ -20,132 +20,132 @@ const props = defineProps({
 })
 watch(drawer, (newVal) => {
   if (newVal) {
-    loading.value = true;
+    loading.value = true
     getFirstTwoRecordsFromEachStore(db.value).then((data: any) => {
-      dataList.value = data.filter((item: any) => item !== null);
-      count.value = dataList.value.length || 0;
-      loading.value = false;
+      dataList.value = data.filter((item: any) => item !== null)
+      count.value = dataList.value.length || 0
+      loading.value = false
       // console.log('First two records from each store:', data);
     }).catch((error) => {
-      console.error('Error:', error);
-    });
+      console.error('Error:', error)
+    })
   }
 })
 
 function handleDeleteDB() {
   ElMessageBox.confirm(
-      '此操作无法撤销。',
-      '删除全部?',
-      {
-        confirmButtonText: '确认',
-        cancelButtonText: '取消',
-        showClose: false,
-        type: 'warning',
-        center: true,
-      }
+    '此操作无法撤销。',
+    '删除全部?',
+    {
+      confirmButtonText: '确认',
+      cancelButtonText: '取消',
+      showClose: false,
+      type: 'warning',
+      center: true
+    }
   ).then(() => {
-    deleteDB().then((res:any) => {
-      console.log('Database deleted successfully.', res);
+    deleteDB().then((res: any) => {
+      console.log('Database deleted successfully.', res)
       // // 重新加载页面
       // window.location.reload();
     }).catch((error: any) => {
-      console.error('Error deleting database:', error);
-    });
+      console.error('Error deleting database:', error)
+    })
   }).catch(() => {
-  });
+  })
 }
 
 function getFirstTwoRecordsFromObjectStoreWithCursor(db: any, storeName: any) {
   return new Promise((resolve, reject) => {
-    const transaction = db.transaction([storeName], 'readonly');
-    const objectStore = transaction.objectStore(storeName);
-    const request = objectStore.openCursor();
-    const results: any[] = [];
-    let count = 0;
+    const transaction = db.transaction([storeName], 'readonly')
+    const objectStore = transaction.objectStore(storeName)
+    const request = objectStore.openCursor()
+    const results: any[] = []
+    let count = 0
 
     request.onerror = (event: any) => {
-      reject(`Failed to get data from object store ${storeName}: ${event.target.error}`);
-    };
+      reject(`Failed to get data from object store ${storeName}: ${event.target.error}`)
+    }
 
     request.onsuccess = (event: any) => {
-      const cursor = event.target.result;
+      const cursor = event.target.result
       if (cursor && count < 2) {
-        results.push(cursor.value);
-        count++;
-        cursor.continue();
+        results.push(cursor.value)
+        count++
+        cursor.continue()
       } else {
         if (results.length) {
           resolve({
             storeName: storeName,
             data: results
-          });
+          })
         } else {
           resolve(null)
         }
       }
-    };
-  });
+    }
+  })
 }
 
 async function getFirstTwoRecordsFromEachStore(db: any) {
   return new Promise((resolve, reject) => {
     // 获取所有对象存储的名称
-    const storeNames = Array.from(db.objectStoreNames);
-    const result: any[] = [];
+    const storeNames = Array.from(db.objectStoreNames)
+    const result: any[] = []
 
     // 遍历每个对象存储并获取前 2 条数据
     const promises = storeNames.map((storeName) => {
-      return getFirstTwoRecordsFromObjectStoreWithCursor(db, storeName);
-    });
+      return getFirstTwoRecordsFromObjectStoreWithCursor(db, storeName)
+    })
 
     // 等待所有对象存储的数据读取完成
     Promise.all(promises).then((dataArrays) => {
       // 将每个对象存储的数据合并到结果数组中
       dataArrays.forEach((data: any) => {
-        result.push(data);
-      });
-      resolve(result);
+        result.push(data)
+      })
+      resolve(result)
     }).catch((error) => {
-      reject(error);
-    });
+      reject(error)
+    })
   })
 }
 
 function handleDeleteStore(e: any, item: any) {
-  e.stopPropagation();
-  if (dataList.value.length < 2){
+  e.stopPropagation()
+  if (dataList.value.length < 2) {
     ElMessage({
       message: '不可删除',
       grouping: true,
       showClose: true
-    });
-    return;
+    })
+    return
   }
   ElMessageBox.confirm(
-      '此操作无法撤销。',
-      '要删除此对话吗?',
-      {
-        confirmButtonText: '确认',
-        cancelButtonText: '取消',
-        type: 'warning',
-        showClose: false,
-        center: true,
-      }
+    '此操作无法撤销。',
+    '要删除此对话吗?',
+    {
+      confirmButtonText: '确认',
+      cancelButtonText: '取消',
+      type: 'warning',
+      showClose: false,
+      center: true
+    }
   ).then(() => {
     useStore(item).clearAll().then((res: any) => {
-      loading.value = true;
+      loading.value = true
       getFirstTwoRecordsFromEachStore(db.value).then((data: any) => {
-        dataList.value = data.filter((item: any) => item !== null);
-        count.value = dataList.value.length || 0;
-        loading.value = false;
+        dataList.value = data.filter((item: any) => item !== null)
+        count.value = dataList.value.length || 0
+        loading.value = false
         // if (item === props.msgUuid) {
         //   const result = getNextOrPreviousId(dataList.value, item);
         //   emit('currentData', result)
         // }
       }).catch((error) => {
-        console.error('Error:', error);
-      });
-    });
+        console.error('Error:', error)
+      })
+    })
   }).catch(() => {
   })
 
@@ -154,19 +154,19 @@ function handleDeleteStore(e: any, item: any) {
 
 
 function getNextOrPreviousId(array: any, currentId: any) {
-  const currentIndex = array.findIndex((item: any) => item.storeName === currentId);
+  const currentIndex = array.findIndex((item: any) => item.storeName === currentId)
 
   if (currentIndex === -1) {
-    throw new Error("当前 storeName 不在数组中");
+    throw new Error('当前 storeName 不在数组中')
   }
 
   if (currentIndex < array.length - 1) {
-    return array[currentIndex + 1].storeName; // 返回下一个对象的 id
+    return array[currentIndex + 1].storeName // 返回下一个对象的 id
   } else if (currentIndex > 0) {
-    return array[currentIndex - 1].storeName; // 返回上一个对象的 id
+    return array[currentIndex - 1].storeName // 返回上一个对象的 id
   }
 
-  return null; // 没有下一个或上一个对象
+  return null // 没有下一个或上一个对象
 }
 
 defineExpose({
@@ -185,9 +185,9 @@ defineExpose({
     <div style="height: 100%;overflow: hidden;" v-loading="loading">
       <div class="his_delete">
         <el-input style="margin-right: 12px" v-model="input" placeholder="搜索" clearable :prefix-icon="Search"
-                  :disabled="true"/>
+                  :disabled="true" />
         <el-tooltip effect="dark" content="删除全部" placement="top">
-          <el-button :icon="Delete" circle @click="handleDeleteDB"/>
+          <el-button :icon="Delete" circle @click="handleDeleteDB" />
         </el-tooltip>
       </div>
       <div class="his_content">
@@ -199,7 +199,7 @@ defineExpose({
             <p class="his_list_op">
               <span>{{ item.data[0]?.timestamp }}</span>
               <el-tooltip effect="dark" content="删除" placement="top">
-                <el-button :icon="Delete" link @click="(e:any)=>handleDeleteStore(e,item.storeName)"/>
+                <el-button :icon="Delete" link @click="(e:any)=>handleDeleteStore(e,item.storeName)" />
               </el-tooltip>
 
             </p>

+ 33 - 33
src/entrypoints/sidepanel/component/inputArea.vue

@@ -1,7 +1,7 @@
 <script setup>
-import { ref } from "vue";
-import { options } from "@/entrypoints/sidepanel/mock";
-import { Reading, Upload, Paperclip, Scissor, AlarmClock, CirclePlus } from "@element-plus/icons-vue";
+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)
@@ -12,40 +12,40 @@ const emit = defineEmits(['readClick', 'uploadFile', 'handleCapture', 'addNewDia
 </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 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-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>
+        <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>
 

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

@@ -1,9 +1,9 @@
 <script setup lang="ts">
-import {ref} from "vue";
-import {options} from "@/entrypoints/sidepanel/mock";
-import {Reading, Upload, Paperclip, Scissor, AlarmClock, CirclePlus} from "@element-plus/icons-vue";
+import { ref } from 'vue'
+import { options } from '@/entrypoints/sidepanel/mock'
+import { Reading, Upload, Paperclip, Scissor, AlarmClock, CirclePlus } from '@element-plus/icons-vue'
 
-const value = ref(options[0].value);
+const value = ref(options[0].value)
 
 const emit = defineEmits(['readClick', 'uploadFile', 'handleCapture', 'addNewDialogue', 'hisRecords'])
 </script>
@@ -13,33 +13,33 @@ const emit = defineEmits(['readClick', 'uploadFile', 'handleCapture', 'addNewDia
     <div class="flex items-center">
       <el-select v-model="value" placeholder="Select" style="width: 120px">
         <el-option-group v-for="group in options" :key="group.label" :label="group.label">
-          <el-option v-for="item in group.options" :key="item.value" :label="item.label" :value="item.value"/>
+          <el-option v-for="item in group.options" :key="item.value" :label="item.label" :value="item.value" />
         </el-option-group>
 
       </el-select>
       <span class="mr-2"></span>
       <el-tooltip effect="dark" content="阅读此页,开启后将会根据左侧网页中的内容做出回答" placement="top">
-        <el-button style="font-size:18px" link :icon="Reading" circle @click="emit('readClick')"/>
+        <el-button style="font-size:18px" link :icon="Reading" circle @click="emit('readClick')" />
       </el-tooltip>
       <span class="mr-2"></span>
       <el-upload style="display:inline-block" :before-upload="(file: any) => emit('uploadFile', file)" :multiple="false"
                  name="file" :show-file-list="false" :accept="'.xlsx,.pdf,.doc,.docx'">
         <el-tooltip effect="dark" content="文件上传" placement="top">
-          <el-button style="font-size:18px" link :icon="Paperclip" circle/>
+          <el-button style="font-size:18px" link :icon="Paperclip" circle />
         </el-tooltip>
       </el-upload>
       <span class="mr-2"></span>
-            <el-tooltip effect="dark" content="截屏" placement="top">
-              <el-button style="font-size:14px" :icon="Scissor" circle @click="emit('handleCapture')" />
-            </el-tooltip>
+      <el-tooltip effect="dark" content="截屏" placement="top">
+        <el-button style="font-size:14px" :icon="Scissor" circle @click="emit('handleCapture')" />
+      </el-tooltip>
     </div>
     <div class="flex items-center">
       <el-tooltip effect="dark" content="历史记录" placement="top">
-        <el-button style="font-size:18px" link :icon="AlarmClock" circle @click="emit('hisRecords')"/>
+        <el-button style="font-size:18px" link :icon="AlarmClock" circle @click="emit('hisRecords')" />
       </el-tooltip>
       <span class="mr-2"></span>
       <el-tooltip effect="dark" content="新对话" placement="top">
-        <el-button style="font-size:18px" link :icon="CirclePlus" circle @click="emit('addNewDialogue')"/>
+        <el-button style="font-size:18px" link :icon="CirclePlus" circle @click="emit('addNewDialogue')" />
       </el-tooltip>
     </div>
   </div>

+ 198 - 198
src/entrypoints/sidepanel/css/chat.scss

@@ -1,323 +1,323 @@
 .els {
-    white-space: nowrap; /* 强制文本不换行 */
-    overflow: hidden; /* 隐藏溢出内容 */
-    text-overflow: ellipsis; /* 显示省略号 */
+  white-space: nowrap; /* 强制文本不换行 */
+  overflow: hidden; /* 隐藏溢出内容 */
+  text-overflow: ellipsis; /* 显示省略号 */
 }
 
 .chat-container {
-    border-radius: 14px;
-    height: 100%;
-    display: flex;
-    flex-direction: column;
-    border: 1px solid #dcdfe6;
-    background-color: #F0F0F0;
-    //background-color: #ffffff;
+  border-radius: 14px;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  border: 1px solid #dcdfe6;
+  background-color: #F0F0F0;
+  //background-color: #ffffff;
 }
 
 .message-list {
-    flex: 1;
-    padding: 16px;
-    overflow: auto;
+  flex: 1;
+  padding: 16px;
+  overflow: auto;
 }
 
 .messages {
-    min-height: 100%;
-    display: flex;
-    flex-direction: column;
+  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;
+  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);
-    }
+  from {
+    opacity: 0;
+    transform: translateY(10px);
+  }
 
-    to {
-        opacity: 1;
-        transform: translateY(0);
-    }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
 }
 
 .message-item.self {
-    flex-direction: row-reverse;
+  flex-direction: row-reverse;
 }
 
 .message-content {
-    max-width: 80%;
+  max-width: 80%;
 }
 
 .username {
-    font-size: 14px;
-    color: #606266;
-    margin-bottom: 4px;
+  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;
+  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;
+  margin: 10px 0;
+  border-radius: 8px;
 }
 
 .content :deep(code) {
-    font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
+  font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
 }
 
 .content :deep(p) {
-    margin: 8px 0;
+  margin: 8px 0;
 }
 
 .content :deep(ul),
 .content :deep(ol) {
-    padding-left: 20px;
-    margin: 8px 0;
+  padding-left: 20px;
+  margin: 8px 0;
 }
 
 .content :deep(blockquote) {
-    border-left: 4px solid #ddd;
-    padding-left: 10px;
-    color: #666;
-    margin: 8px 0;
+  border-left: 4px solid #ddd;
+  padding-left: 10px;
+  color: #666;
+  margin: 8px 0;
 }
 
 .self .content {
-    background: #409eff;
-    color: white;
-    border-bottom-right-radius: 4px;
+  background: #409eff;
+  color: white;
+  border-bottom-right-radius: 4px;
 }
 
 .other .content {
-    border-bottom-left-radius: 4px;
+  border-bottom-left-radius: 4px;
 }
 
 .timestamp {
-    display: flex;
-    justify-content: space-between;
-    font-size: 12px;
-    color: #909399;
-    margin-top: 6px;
+  display: flex;
+  justify-content: space-between;
+  font-size: 12px;
+  color: #909399;
+  margin-top: 6px;
 }
 
 .timestamp span {
-    transition: color 0.2s;
+  transition: color 0.2s;
 }
 
 .timestamp span:hover {
-    color: #409eff;
+  color: #409eff;
 }
 
 .info-card {
-    margin: 10px;
+  margin: 10px;
 }
 
 .card-icon {
-    color: #409eff;
+  color: #409eff;
 }
 
 
 @keyframes scrollTitle {
-    0% {
-        transform: translateX(0);
-    }
+  0% {
+    transform: translateX(0);
+  }
 
-    100% {
-        transform: translateX(-100%);
-    }
+  100% {
+    transform: translateX(-100%);
+  }
 }
 
 .upload :deep(.el-icon) {
-    transition: color 0.3s;
+  transition: color 0.3s;
 }
 
 .can-hover :deep(.el-icon:hover) {
-    color: #409eff !important;
+  color: #409eff !important;
 }
 
 .el-check-tag {
-    margin-right: 8px;
-    transition: all 0.3s;
+  margin-right: 8px;
+  transition: all 0.3s;
 }
 
 .el-check-tag:hover {
-    transform: scale(1.05);
+  transform: scale(1.05);
 }
 
 /* 加载中的消息样式 */
 .loading-content {
-    min-height: 40px;
-    display: flex;
-    align-items: center;
-    justify-content: flex-start;
+  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;
-    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;
-    }
+    animation: pulse 1.5s infinite ease-in-out;
+  }
 
-    .dot:nth-child(2) {
-        animation-delay: 0.3s;
-    }
+  .dot:nth-child(2) {
+    animation-delay: 0.3s;
+  }
 
-    .dot:nth-child(3) {
-        animation-delay: 0.6s;
-    }
+  .dot:nth-child(3) {
+    animation-delay: 0.6s;
+  }
 
-    @keyframes pulse {
+  @keyframes pulse {
 
-        0%,
-        100% {
-            transform: scale(0.8);
-            opacity: 0.6;
-        }
+    0%,
+    100% {
+      transform: scale(0.8);
+      opacity: 0.6;
+    }
 
-        50% {
-            transform: scale(1.2);
-            opacity: 1;
-        }
+    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_list {
-        display: flex;
-        flex-wrap: nowrap;
-        overflow-x: auto;
-        padding: 4px 0;
-
-        .card_width {
-            width: 124px !important;
-        }
+  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_list {
+    display: flex;
+    flex-wrap: nowrap;
+    overflow-x: auto;
+    padding: 4px 0;
+
+    .card_width {
+      width: 124px !important;
+    }
+  }
+
+  .card-content {
+    flex-shrink: 0;
+    width: fit-content;
+    max-width: 260px;
+    height: 50px;
+    display: flex;
+    align-items: center;
+    gap: 6px;
+    padding: 8px 6px;
+    margin: 0 8px 6px 0;
+    background: #fff;
+    border-radius: 10px;
+    border: 1px solid rgba(0, 0, 0, 0.2);
+    font-size: 14px;
+    position: relative;
+
+    .title-wrapper {
+      display: flex;
+      //width: fit-content;
+      width: calc(100% - 30px);
+      flex-direction: column;
     }
 
-    .card-content {
-        flex-shrink: 0;
-        width: fit-content;
-        max-width: 260px;
-        height: 50px;
-        display: flex;
-        align-items: center;
-        gap: 6px;
-        padding: 8px 6px;
-        margin: 0 8px 6px 0;
-        background: #fff;
-        border-radius: 10px;
-        border: 1px solid rgba(0, 0, 0, 0.2);
-        font-size: 14px;
-        position: relative;
-
-        .title-wrapper {
-            display: flex;
-            //width: fit-content;
-            width: calc(100% - 30px);
-            flex-direction: column;
-        }
-
-
-        .title-scroller {
-            display: inline-block;
-            white-space: nowrap;
-            color: #000000;
-            font-size: 14px;
-            font-weight: 900;
-        }
-
-        .url-scroller {
-            font-size: 12px;
-            color: #909399;
-        }
-
-        .title-scroller.scroll {
-            animation: scrollTitle 10s linear infinite;
-        }
-
-        .closeIcon {
-            display: none;
-            position: absolute;
-            right: -5px;
-            top: -5px;
-            background-color: #ffffff;
-            border-radius: 50%;
-            z-index: 1;
-        }
 
+    .title-scroller {
+      display: inline-block;
+      white-space: nowrap;
+      color: #000000;
+      font-size: 14px;
+      font-weight: 900;
     }
 
-    .card-content:hover {
-        .closeIcon {
-            display: block;
-        }
+    .url-scroller {
+      font-size: 12px;
+      color: #909399;
     }
 
-    .card-btn {
-        padding: 0 0 4px;
+    .title-scroller.scroll {
+      animation: scrollTitle 10s linear infinite;
+    }
 
-        .op {
-            margin-right: 3px;
-        }
+    .closeIcon {
+      display: none;
+      position: absolute;
+      right: -5px;
+      top: -5px;
+      background-color: #ffffff;
+      border-radius: 50%;
+      z-index: 1;
     }
 
-    .chat_area_op {
-        margin-top: 3px;
-        display: flex;
-        justify-content: end;
+  }
+
+  .card-content:hover {
+    .closeIcon {
+      display: block;
+    }
+  }
+
+  .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);
+  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;
+  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;
+  padding: 0 4px;
+  margin-top: 3px;
 }
 
 .input-area :deep(.el-textarea__inner:focus) {
-    border-color: #409eff;
-    box-shadow: none;
+  border-color: #409eff;
+  box-shadow: none;
 }

+ 13 - 13
src/entrypoints/sidepanel/hook/useAutoResizeTextarea.ts

@@ -1,23 +1,23 @@
-import { ref, watch, onMounted } from 'vue';
+import { ref, watch, onMounted } from 'vue'
 
 export function useAutoResizeTextarea(textareaRef: any, text: any) {
 
   const adjustHeight = () => {
-    const textarea = textareaRef.value.ref;
-    textarea.style.height = 'auto'; // 重置高度
-    textarea.style.height = `${textarea.scrollHeight}px`; // 设置新高度
-    textarea.style['max-height'] = '240px';
-    textarea.style['min-height'] = '54px';
-  };
+    const textarea = textareaRef.value.ref
+    textarea.style.height = 'auto' // 重置高度
+    textarea.style.height = `${textarea.scrollHeight}px` // 设置新高度
+    textarea.style['max-height'] = '240px'
+    textarea.style['min-height'] = '54px'
+  }
   watch(text, (newVal) => {
     if (newVal === '') {
-      textareaRef.value.ref.style.height = '54px';
-      return;
+      textareaRef.value.ref.style.height = '54px'
+      return
     }
-    adjustHeight();
-  });
+    adjustHeight()
+  })
 
   onMounted(() => {
-    adjustHeight(); // 初始化时调整高度
-  });
+    adjustHeight() // 初始化时调整高度
+  })
 }

+ 184 - 184
src/entrypoints/sidepanel/hook/useIndexedDB.ts

@@ -1,210 +1,210 @@
-import {ref, readonly} from 'vue'
+import { ref, readonly } from 'vue'
 
 interface IndexedDBStoreConfig {
+  name: string;
+  keyPath: string;
+  indexes?: Array<{
     name: string
-    keyPath: string
-    indexes?: Array<{
-        name: string
-        keyPath: string | string[]
-        options?: IDBIndexParameters
-    }>
+    keyPath: string | string[]
+    options?: IDBIndexParameters
+  }>;
 }
 
 interface IndexedDBConfig {
-    dbName: string
-    version?: number
+  dbName: string;
+  version?: number;
 }
 
 // 全局存储Store配置
 const storeRegistry = new Map<string, IndexedDBStoreConfig>()
 
 export function useIndexedDB(config: IndexedDBConfig) {
-    const dbName = ref<any>(config.dbName);
-    const db = ref<IDBDatabase | null>(null)
-    const currentVersion = ref(config?.version || 1)
-    const isInitialized = ref(false)
-
-    // 注册Store配置(业务模块调用)
-    const registerStore = (storeConfig: IndexedDBStoreConfig) => {
-        if (!storeRegistry.has(storeConfig.name)) {
-            storeRegistry.set(storeConfig.name, storeConfig)
-        }
+  const dbName = ref<any>(config.dbName)
+  const db = ref<IDBDatabase | null>(null)
+  const currentVersion = ref(config?.version || 1)
+  const isInitialized = ref(false)
+
+  // 注册Store配置(业务模块调用)
+  const registerStore = (storeConfig: IndexedDBStoreConfig) => {
+    if (!storeRegistry.has(storeConfig.name)) {
+      storeRegistry.set(storeConfig.name, storeConfig)
     }
-    const deleteDB = () => {
-        return new Promise((resolve, reject) => {
-            const request = indexedDB.deleteDatabase(dbName.value);
-            window.location.reload();
-            request.onsuccess = () => {
-                resolve(true)
-            }
-            request.onerror = () => {
-                reject(request.error)
-            }
+  }
+  const deleteDB = () => {
+    return new Promise((resolve, reject) => {
+      const request = indexedDB.deleteDatabase(dbName.value)
+      window.location.reload()
+      request.onsuccess = () => {
+        resolve(true)
+      }
+      request.onerror = () => {
+        reject(request.error)
+      }
+    })
+  }
+  const openDB = (): Promise<IDBDatabase> => {
+    return new Promise((resolve, reject) => {
+      const request = indexedDB.open(dbName.value, currentVersion.value)
+
+      request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
+
+        const db = (event.target as IDBOpenDBRequest).result
+
+        // 从注册中心获取所有Store配置
+        const stores = Array.from(storeRegistry.values())
+
+        stores.forEach(storeConfig => {
+          if (!db.objectStoreNames.contains(storeConfig.name)) {
+            const objectStore = db.createObjectStore(
+              storeConfig.name,
+              { keyPath: storeConfig.keyPath }
+            )
+
+            storeConfig.indexes?.forEach(index => {
+              objectStore.createIndex(
+                index.name,
+                index.keyPath,
+                index.options
+              )
+            })
+          }
         })
-    }
-    const openDB = (): Promise<IDBDatabase> => {
-        return new Promise((resolve, reject) => {
-            const request = indexedDB.open(dbName.value, currentVersion.value)
-
-            request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
-
-                const db = (event.target as IDBOpenDBRequest).result;
-
-                // 从注册中心获取所有Store配置
-                const stores = Array.from(storeRegistry.values())
-
-                stores.forEach(storeConfig => {
-                    if (!db.objectStoreNames.contains(storeConfig.name)) {
-                        const objectStore = db.createObjectStore(
-                            storeConfig.name,
-                            {keyPath: storeConfig.keyPath}
-                        )
-
-                        storeConfig.indexes?.forEach(index => {
-                            objectStore.createIndex(
-                                index.name,
-                                index.keyPath,
-                                index.options
-                            )
-                        })
-                    }
-                })
-            }
-
-            request.onsuccess = (event: Event) => {
-                db.value = (event.target as IDBOpenDBRequest).result
-                isInitialized.value = true
-                Array.from(db.value.objectStoreNames).forEach((storeName: any) => {
-                    registerStore({
-                        name: storeName,
-                        keyPath: 'id',
-                    })
-                })
-                resolve(db.value)
-            }
-
-            request.onerror = (event: Event) => {
-                reject((event.target as IDBOpenDBRequest).error)
-            }
+      }
+
+      request.onsuccess = (event: Event) => {
+        db.value = (event.target as IDBOpenDBRequest).result
+        isInitialized.value = true
+        Array.from(db.value.objectStoreNames).forEach((storeName: any) => {
+          registerStore({
+            name: storeName,
+            keyPath: 'id'
+          })
         })
+        resolve(db.value)
+      }
+
+      request.onerror = (event: Event) => {
+        reject((event.target as IDBOpenDBRequest).error)
+      }
+    })
+  }
+
+  // 动态升级数据库版本
+  const upgradeVersion = async () => {
+    currentVersion.value += 1
+    localStorage.setItem('dbVersion', currentVersion.value.toString())
+    db.value?.close()
+    return openDB()
+  }
+
+  const useStore = <T>(storeName: string) => {
+    const verifyStore = async () => {
+      if (!storeRegistry.has(storeName)) {
+        throw new Error(`Store ${storeName} not registered`)
+      }
+
+      if (db.value && !db.value.objectStoreNames.contains(storeName)) {
+        await upgradeVersion()
+      }
     }
 
-    // 动态升级数据库版本
-    const upgradeVersion = async () => {
-        currentVersion.value += 1
-        localStorage.setItem('dbVersion', currentVersion.value.toString());
-        db.value?.close()
-        return openDB()
-    }
+    const executeWithTransaction = async <R>(
+      mode: IDBTransactionMode,
+      operation: (store: IDBObjectStore) => Promise<R>
+    ): Promise<R> => {
+      await verifyStore()
 
-    const useStore = <T>(storeName: string) => {
-        const verifyStore = async () => {
-            if (!storeRegistry.has(storeName)) {
-                throw new Error(`Store ${storeName} not registered`)
-            }
+      if (!db.value) await openDB()
 
-            if (db.value && !db.value.objectStoreNames.contains(storeName)) {
-                await upgradeVersion()
-            }
-        }
+      return new Promise((resolve, reject) => {
+        db.value
+        const transaction = db.value!.transaction(storeName, mode)
+        const objectStore = transaction.objectStore(storeName)
 
-        const executeWithTransaction = async <R>(
-            mode: IDBTransactionMode,
-            operation: (store: IDBObjectStore) => Promise<R>
-        ): Promise<R> => {
-            await verifyStore();
-
-            if (!db.value) await openDB();
-
-            return new Promise((resolve, reject) => {
-                db.value;
-                const transaction = db.value!.transaction(storeName, mode);
-                const objectStore = transaction.objectStore(storeName);
-
-                // 事务成功完成时的回调
-                // transaction.oncomplete = () => {
-                //     resolve(); // 事务成功完成,返回结果
-                // };
-
-                // 事务失败时的回调
-                transaction.onerror = (event) => {
-                    reject((event.target as IDBRequest).error);
-                };
-
-                // 执行操作
-                operation(objectStore).then((result) => {
-                    // 操作成功,返回结果
-                    resolve(result);
-                }).catch((error) => {
-                    // 操作失败,拒绝 Promise
-                    reject(error);
-                });
-            });
-        };
-
-
-        return {
-            add: (data: T) => executeWithTransaction(
-                'readwrite',
-                (store) => new Promise((resolve, reject) => {
-                    const request = store.add(data)
-                    request.onsuccess = () => resolve(request.result as IDBValidKey)
-                    request.onerror = () => reject(request.error)
-                })
-            ),
-
-            get: (key: IDBValidKey) => executeWithTransaction(
-                'readonly',
-                (store) => new Promise((resolve, reject) => {
-                    const request = store.get(key)
-                    request.onsuccess = () => resolve(request.result as T | undefined)
-                    request.onerror = () => reject(request.error)
-                })
-            ),
-
-            update: (data: T) => executeWithTransaction(
-                'readwrite',
-                (store) => new Promise((resolve, reject) => {
-                    const request = store.put(data)
-                    request.onsuccess = () => resolve(request.result as IDBValidKey)
-                    request.onerror = () => reject(request.error)
-                })
-            ),
-
-            delete: (key: IDBValidKey) => executeWithTransaction(
-                'readwrite',
-                (store) => new Promise((resolve, reject) => {
-                    const request = store.delete(key)
-                    request.onsuccess = () => resolve(undefined)
-                    request.onerror = () => reject(request.error)
-                })
-            ),
-
-            getAll: () => executeWithTransaction(
-                'readonly',
-                (store) => new Promise((resolve, reject) => {
-                    const request = store.getAll()
-                    request.onsuccess = () => resolve(request.result as T[])
-                    request.onerror = () => reject(request.error)
-                })
-            ),
-            clearAll: () => executeWithTransaction(
-                'readwrite',
-                (store) => new Promise((resolve, reject) => {
-                    const request = store.clear()
-                    request.onsuccess = () => resolve(true)
-                    request.onerror = () => reject(request.error)
-                })
-            )
+        // 事务成功完成时的回调
+        // transaction.oncomplete = () => {
+        //     resolve(); // 事务成功完成,返回结果
+        // };
+
+        // 事务失败时的回调
+        transaction.onerror = (event) => {
+          reject((event.target as IDBRequest).error)
         }
+
+        // 执行操作
+        operation(objectStore).then((result) => {
+          // 操作成功,返回结果
+          resolve(result)
+        }).catch((error) => {
+          // 操作失败,拒绝 Promise
+          reject(error)
+        })
+      })
     }
 
+
     return {
-        db,
-        openDB,
-        deleteDB,
-        registerStore,
-        useStore,
-        isInitialized
+      add: (data: T) => executeWithTransaction(
+        'readwrite',
+        (store) => new Promise((resolve, reject) => {
+          const request = store.add(data)
+          request.onsuccess = () => resolve(request.result as IDBValidKey)
+          request.onerror = () => reject(request.error)
+        })
+      ),
+
+      get: (key: IDBValidKey) => executeWithTransaction(
+        'readonly',
+        (store) => new Promise((resolve, reject) => {
+          const request = store.get(key)
+          request.onsuccess = () => resolve(request.result as T | undefined)
+          request.onerror = () => reject(request.error)
+        })
+      ),
+
+      update: (data: T) => executeWithTransaction(
+        'readwrite',
+        (store) => new Promise((resolve, reject) => {
+          const request = store.put(data)
+          request.onsuccess = () => resolve(request.result as IDBValidKey)
+          request.onerror = () => reject(request.error)
+        })
+      ),
+
+      delete: (key: IDBValidKey) => executeWithTransaction(
+        'readwrite',
+        (store) => new Promise((resolve, reject) => {
+          const request = store.delete(key)
+          request.onsuccess = () => resolve(undefined)
+          request.onerror = () => reject(request.error)
+        })
+      ),
+
+      getAll: () => executeWithTransaction(
+        'readonly',
+        (store) => new Promise((resolve, reject) => {
+          const request = store.getAll()
+          request.onsuccess = () => resolve(request.result as T[])
+          request.onerror = () => reject(request.error)
+        })
+      ),
+      clearAll: () => executeWithTransaction(
+        'readwrite',
+        (store) => new Promise((resolve, reject) => {
+          const request = store.clear()
+          request.onsuccess = () => resolve(true)
+          request.onerror = () => reject(request.error)
+        })
+      )
     }
+  }
+
+  return {
+    db,
+    openDB,
+    deleteDB,
+    registerStore,
+    useStore,
+    isInitialized
+  }
 }

+ 135 - 135
src/entrypoints/sidepanel/hook/useMsg.ts

@@ -1,181 +1,181 @@
 // 消息数组
-import { ref, reactive, nextTick, inject } from "vue";
-import { storeToRefs } from "pinia";
-import avator from "@/public/icon/32.png";
-import moment from "moment";
-import { getFormKey, buildObjPrompt, getFileSummaryPrompt } from "@/utils/ai-service";
-import { ElMessage } from "element-plus";
-import { getPageInfo } from "../utils/index.js";
-import { mockData, mockData2 } from "../mock";
-import { useMsgStore } from "@/store/modules/msg";
+import { ref, reactive, nextTick, inject } from 'vue'
+import { storeToRefs } from 'pinia'
+import avator from '@/public/icon/32.png'
+import moment from 'moment'
+import { getFormKey, buildObjPrompt, getFileSummaryPrompt } from '@/utils/ai-service'
+import { ElMessage } from 'element-plus'
+import { getPageInfo } from '../utils/index.js'
+import { mockData, mockData2 } from '../mock'
+import { useMsgStore } from '@/store/modules/msg'
 
 // import { sendMessage } from '@/utils/ai-service';
 export function useMsg(scrollbar?: any) {
-  const { messages,msgUuid } = storeToRefs(useMsgStore());
-  const indexTemp = ref(0);
-  const taklToHtml = ref<any>(false);
-  const sendLoading = ref(false);
-  const pageInfo = ref<any>({});
-  const type = ref("");
-  const formMap = ref([]);
+  const { messages, msgUuid } = storeToRefs(useMsgStore())
+  const indexTemp = ref(0)
+  const taklToHtml = ref<any>(false)
+  const sendLoading = ref(false)
+  const pageInfo = ref<any>({})
+  const type = ref('')
+  const formMap = ref([])
   // 获取父组件提供的 Hook 实例
-  const { useStore } = inject("indexedDBHook") as any;
+  const { useStore } = inject('indexedDBHook') as any
 
   const getFileSummary = async (file: any) => {
     const obj = reactive({
       id: moment(),
-      username: "用户1",
-      rawContent: "",
-      content: "解析文件中",
-      timestamp: moment().format("YYYY-MM-DD HH:mm:ss"),
+      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));
-      const res = await getFileValue(file);
-      console.log(res.data, file);
-      await streamRes();
+      sendLoading.value = true
+      messages.value.push(obj)
+      nextTick(() => scrollbar.value?.setScrollTop(99999))
+      const res = await getFileValue(file)
+      console.log(res.data, file)
+      await streamRes()
     } catch (error) {
-      obj.content = "解析出错";
+      obj.content = '解析出错'
     } finally {
-      sendLoading.value = false;
+      sendLoading.value = false
     }
-  };
+  }
   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"),
+      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);
+      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));
+      })
+      return response
+      xlsxData.value = response.data
+      console.log(xlsxData.value)
+      console.log(type.value)
+      await streamRes(buildObjPrompt(response.data, form))
     } catch (error) {
-      obj.content = "解析出错";
+      obj.content = '解析出错'
     } finally {
-      sendLoading.value = false;
+      sendLoading.value = false
     }
-  };
+  }
   // 发送消息
   const handleSend = async (msg: any, addHtml = false) => {
-    if ((type.value === "2" && msg.startsWith("/")) || 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"),
+        username: '用户1',
+        content: '请打开与页面对话!',
+        rawContent: '请打开与页面对话!',
+        timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
         isSelf: false,
         avatar: avator,
         addToHistory: false
-      });
-      indexTemp.value = 0;
-      fetchRes(msg);
+      })
+      indexTemp.value = 0
+      fetchRes(msg)
     } else {
-      streamRes(addHtml);
+      streamRes(addHtml)
     }
-  };
+  }
   const fetchRes = async (msg: any) => {
-    sendLoading.value = true;
+    sendLoading.value = true
     const obj: any = reactive({
       id: messages.value.length + 1,
-      username: "用户1",
-      content: "",
-      timestamp: moment().format("YYYY-MM-DD HH:mm:ss"),
+      username: '用户1',
+      content: '',
+      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
       isSelf: false,
       avatar: avator,
       addToHistory: !taklToHtml.value
-    });
-    messages.value.push(obj);
-    nextTick(() => scrollbar.value?.setScrollTop(99999));
-    await fetchDataAndProcess(msg, obj);
-    sendLoading.value = false;
-  };
-  let str = "";
+    })
+    messages.value.push(obj)
+    nextTick(() => scrollbar.value?.setScrollTop(99999))
+    await fetchDataAndProcess(msg, obj)
+    sendLoading.value = false
+  }
+  let str = ''
 
   async function fetchDataAndProcess(input: any, obj: any) {
-    if (input.startsWith("/智能填表")) {
-      input = input.split("/智能填表")[1];
+    if (input.startsWith('/智能填表')) {
+      input = input.split('/智能填表')[1]
     }
-    str = input;
-    console.log(str);
-    const pageInfo = await getPageInfo();
+    str = input
+    console.log(str)
+    const pageInfo = await getPageInfo()
     await new Promise((res: any) => setTimeout(() => {
-      res();
-    }, 2000));
+      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;
+        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);
+    await handleClick(res.data, obj)
   }
 
   async function handleClick(res: any, msgObj: any) {
-    await new Promise(resolve => setTimeout(resolve, 2000));
-    msgObj.content = `点击${res.tag}元素`;
+    await new Promise(resolve => setTimeout(resolve, 2000))
+    msgObj.content = `点击${res.tag}元素`
     chrome.runtime.sendMessage({
-      type: "FROM_SIDE_PANEL_TO_ACTION",
+      type: 'FROM_SIDE_PANEL_TO_ACTION',
       data: res
     }, async ({ data, status }) => {
       if (chrome.runtime.lastError) {
-        console.error("消息发送错误:", chrome.runtime.lastError);
+        console.error('消息发送错误:', chrome.runtime.lastError)
       } else {
-        if (status === "error") {
-          msgObj.content = data;
-          return;
+        if (status === 'error') {
+          msgObj.content = data
+          return
         }
-        if (res.next === "是") {
-          const arr = str.split(",");
-          arr.shift();
-          str = arr.join(",");
-          indexTemp.value++;
-          fetchDataAndProcess(str, msgObj);
+        if (res.next === '是') {
+          const arr = str.split(',')
+          arr.shift()
+          str = arr.join(',')
+          indexTemp.value++
+          fetchDataAndProcess(str, msgObj)
         } else {
-          if (type.value === "2") {
+          if (type.value === '2') {
             await new Promise((resolve, reject) => {
               setTimeout(() => {
-                resolve(1);
-              }, 2000);
-            });
-            msgObj.content = `请上传数据`;
-            ElMessage({ message: "请上传数据", type: "success", duration: 4 * 1000, grouping: true });
+                resolve(1)
+              }, 2000)
+            })
+            msgObj.content = `请上传数据`
+            ElMessage({ message: '请上传数据', type: 'success', duration: 4 * 1000, grouping: true })
           } else {
-            msgObj.content = `执行完毕`;
+            msgObj.content = `执行完毕`
           }
         }
       }
-      return true;
-    });
+      return true
+    })
 
   }
 
@@ -184,66 +184,66 @@ export function useMsg(scrollbar?: any) {
    * @param addHtml 是否添加页面信息
    */
   const streamRes = async (addHtml: any = false) => {
-    pageInfo.value = await getPageInfo();
-    sendLoading.value = true;
+    pageInfo.value = await getPageInfo()
+    sendLoading.value = true
     const obj = reactive<any>({
       id: messages.value.length + 1,
-      username: "用户1",
-      content: "",
-      rawContent: "", // 存储原始内容
-      timestamp: moment().format("YYYY-MM-DD HH:mm:ss"),
+      username: '用户1',
+      content: '',
+      rawContent: '', // 存储原始内容
+      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
       isSelf: false,
       avatar: avator,
       addToHistory: !taklToHtml.value
-    });
-    let history = [];
+    })
+    let history = []
     if (taklToHtml.value) {
       if (addHtml) {
         history.push({
-          role: "user",
+          role: 'user',
           content: `页面主要内容${pageInfo.value.content.mainContent}`
-        });
+        })
       }
       history.push({
-        role: "user",
+        role: 'user',
         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",
+          role: item.isSelf ? 'user' : 'system',
           content: item.rawContent
-        }));
+        }))
 
     }
 
-    messages.value.push(obj);
+    messages.value.push(obj)
     nextTick(() => {
-      scrollbar.value?.setScrollTop(99999);
-    });
-    const iterator = await sendMessage(history);
+      scrollbar.value?.setScrollTop(99999)
+    })
+    const iterator = await sendMessage(history)
     for await (const chunk of iterator) {
       if (chunk) {
-        const decodedChunk = chunk.choices[0].delta.content;
+        const decodedChunk = chunk.choices[0].delta.content
         if (decodedChunk) {
           // 保存原始内容
-          obj.rawContent += decodedChunk;
+          obj.rawContent += decodedChunk
           // 实时格式化显示内容
-          obj.content = formatMessage(obj.rawContent);
+          obj.content = formatMessage(obj.rawContent)
         }
       }
-      scrollbar.value?.setScrollTop(99999);
+      scrollbar.value?.setScrollTop(99999)
     }
     //添加到存储历史
-    useStore(msgUuid.value).add({ ...obj });
+    useStore(msgUuid.value).add({ ...obj })
     // 处理最终内容
-    sendLoading.value = false;
+    sendLoading.value = false
     nextTick(() => {
-      scrollbar.value?.setScrollTop(99999);
-    });
-    return obj.rawContent;
-  };
+      scrollbar.value?.setScrollTop(99999)
+    })
+    return obj.rawContent
+  }
   return {
     indexTemp,
     taklToHtml,
@@ -254,5 +254,5 @@ export function useMsg(scrollbar?: any) {
     streamRes,
     getFormKeyAndValue,
     getFileSummary
-  };
+  }
 }

+ 10 - 10
src/entrypoints/sidepanel/index.html

@@ -1,13 +1,13 @@
 <!doctype html>
 <html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>Default Popup Title</title>
-    <meta name="manifest.type" content="browser_action" />
-  </head>
-  <body>
-    <div id="app"></div>
-    <script type="module" src="./main.ts"></script>
-  </body>
+<head>
+  <meta charset="UTF-8" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  <title>Default Popup Title</title>
+  <meta name="manifest.type" content="browser_action" />
+</head>
+<body>
+<div id="app"></div>
+<script type="module" src="./main.ts"></script>
+</body>
 </html>

+ 13 - 13
src/entrypoints/sidepanel/main.ts

@@ -1,17 +1,17 @@
-import { createApp } from "vue";
-import "./style.css";
-import App from "./App.vue";
-import "@/../node_modules/element-plus/dist/index.css";
-import ElementPlus from "element-plus";
-import "element-plus/dist/index.css";
-import locale from "element-plus/es/locale/lang/zh-cn"; // 中文语言
-import * as ElementPlusIconsVue from "@element-plus/icons-vue";
+import { createApp } from 'vue'
+import './style.css'
+import App from './App.vue'
+import '@/../node_modules/element-plus/dist/index.css'
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+import locale from 'element-plus/es/locale/lang/zh-cn' // 中文语言
+import * as ElementPlusIconsVue from '@element-plus/icons-vue'
 
-const app = createApp(App);
-app.use(ElementPlus, { locale: locale, size: "small" });
-app.use(store);
+const app = createApp(App)
+app.use(ElementPlus, { locale: locale, size: 'small' })
+app.use(store)
 for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
-  app.component(key, component);
+  app.component(key, component)
 }
 
-app.mount("#app");
+app.mount('#app')

+ 69 - 21
src/entrypoints/sidepanel/mock.ts

@@ -1,17 +1,17 @@
-import moment from "moment/moment";
-import avator from "@/public/icon/32.png";
+import moment from 'moment/moment'
+import avator from '@/public/icon/32.png'
 
 export const options = [
   {
-    label: "通义千问",
+    label: '通义千问',
     options: [
       {
-        label: "通义千问-Plus",
-        value: "qwen-plus"
+        label: '通义千问-Plus',
+        value: 'qwen-plus'
       },
       {
-        label: "通义千问-Max",
-        value: "qwen-max"
+        label: '通义千问-Max',
+        value: 'qwen-max'
       }
     ]
   }
@@ -37,26 +37,74 @@ export const options = [
   //     value: 'DeepSeek-R1 14B',
   //     label: 'DeepSeek-R1 14B',
   // },
-];
+]
 
 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: "是" },
+  {
+    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 = {
-    id: 1,
-    username: '用户1',
-    content: '你好!有什么我可以帮助你的吗?',
-    rawContent: '你好!有什么我可以帮助你的吗?',
-    timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
-    isSelf: false,
-    avatar: avator
+  id: 1,
+  username: '用户1',
+  content: '你好!有什么我可以帮助你的吗?',
+  rawContent: '你好!有什么我可以帮助你的吗?',
+  timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+  isSelf: false,
+  avatar: avator
 }

+ 40 - 40
src/entrypoints/sidepanel/style.css

@@ -3,80 +3,80 @@
 @tailwind utilities;
 
 :root {
-  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
-  line-height: 1.5;
-  font-weight: 400;
+    font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
+    line-height: 1.5;
+    font-weight: 400;
 
-  color-scheme: light dark;
-  color: rgba(255, 255, 255, 0.87);
-  background-color: #242424;
+    color-scheme: light dark;
+    color: rgba(255, 255, 255, 0.87);
+    background-color: #242424;
 
-  font-synthesis: none;
-  text-rendering: optimizeLegibility;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-  -webkit-text-size-adjust: 100%;
+    font-synthesis: none;
+    text-rendering: optimizeLegibility;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    -webkit-text-size-adjust: 100%;
 }
 
 * {
-  margin: 0;
-  padding: 0;
-  box-sizing: border-box;
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
 }
 
-html,body {
-  height: 100%;
-  min-width: 320px;
-  min-height: 100%;
-  /*background-color: #ffffff;*/
-  background-color: #F6F6F8;
-  font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
+html, body {
+    height: 100%;
+    min-width: 320px;
+    min-height: 100%;
+    /*background-color: #ffffff;*/
+    background-color: #F6F6F8;
+    font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
 }
 
 #app {
-  margin: auto;
-  max-width: 1280px;
-  width: 100%;
-  height: 100%;
-  padding: 4px;
+    margin: auto;
+    max-width: 1280px;
+    width: 100%;
+    height: 100%;
+    padding: 4px;
 }
 
 /* 自定义滚动条样式 */
 ::-webkit-scrollbar {
-  width: 8px;
-  height: 8px;
+    width: 8px;
+    height: 8px;
 }
 
 ::-webkit-scrollbar-track {
-  background: #f1f1f1;
-  border-radius: 4px;
+    background: #f1f1f1;
+    border-radius: 4px;
 }
 
 ::-webkit-scrollbar-thumb {
-  background: #888;
-  border-radius: 4px;
+    background: #888;
+    border-radius: 4px;
 }
 
 ::-webkit-scrollbar-thumb:hover {
-  background: #555;
+    background: #555;
 }
 
 /* 为代码块滚动条设置暗色主题 */
 pre::-webkit-scrollbar-track {
-  background: #343842;
+    background: #343842;
 }
 
 pre::-webkit-scrollbar-thumb {
-  background: #666;
+    background: #666;
 }
 
 pre::-webkit-scrollbar-thumb:hover {
-  background: #888;
+    background: #888;
 }
 
 @media (prefers-color-scheme: light) {
-  :root {
-    color: #213547;
-    background-color: #ffffff;
-  }
+    :root {
+        color: #213547;
+        background-color: #ffffff;
+    }
 }

+ 47 - 46
src/entrypoints/sidepanel/utils/index.js

@@ -1,54 +1,55 @@
-import * as XLSX from "xlsx";
+import * as XLSX from 'xlsx'
+
 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)
-            }
-        });
+  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
-        }
-    })
+  chrome.runtime.sendMessage({
+    type: 'FROM_SIDE_PANEL_TO_INPUT_FORM',
+    data: {
+      excelData: xlsxData,
+      formData: formMap
+    }
+  })
 }
 export const getXlsxValue = (file) => {
-    return new Promise((res, rej) => {
-      try {
-          const reader = new FileReader();
-          reader.readAsArrayBuffer(file)
-          reader.onload =  (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'
-              });
-              res(readData)
-          }
-      } catch (error) {
-        rej()
+  return new Promise((res, rej) => {
+    try {
+      const reader = new FileReader()
+      reader.readAsArrayBuffer(file)
+      reader.onload = (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'
+        })
+        res(readData)
       }
-   })
+    } catch (error) {
+      rej()
+    }
+  })
 }

+ 14 - 13
src/public/wxt.svg

@@ -1,15 +1,16 @@
 <svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g clip-path="url(#clip0_305_516)">
-<g clip-path="url(#clip1_305_516)">
-<path d="M49.0229 69.1875C54.1272 69.1875 58.265 65.0497 58.265 59.9454V50.7033H59.9454C65.0497 50.7033 69.1875 46.5655 69.1875 41.4612C69.1875 36.357 65.0497 32.2191 59.9454 32.2191H58.265V22.9771C58.265 17.8728 54.1272 13.735 49.0229 13.735H39.7809V12.0546C39.7809 6.95032 35.643 2.8125 30.5388 2.8125C25.4345 2.8125 21.2967 6.95032 21.2967 12.0546V13.735H12.0546C6.95032 13.735 2.8125 17.8728 2.8125 22.9771V32.2191H4.49288C9.59714 32.2191 13.735 36.357 13.735 41.4612C13.735 46.5655 9.59714 50.7033 4.49288 50.7033H2.8125V69.1875H21.2967V67.5071C21.2967 62.4029 25.4345 58.265 30.5388 58.265C35.643 58.265 39.7809 62.4029 39.7809 67.5071V69.1875H49.0229Z" stroke="#67D55E" stroke-width="5.625"/>
-</g>
-</g>
-<defs>
-<clipPath id="clip0_305_516">
-<rect width="72" height="72" fill="white"/>
-</clipPath>
-<clipPath id="clip1_305_516">
-<rect width="72" height="72" fill="white"/>
-</clipPath>
-</defs>
+    <g clip-path="url(#clip0_305_516)">
+        <g clip-path="url(#clip1_305_516)">
+            <path d="M49.0229 69.1875C54.1272 69.1875 58.265 65.0497 58.265 59.9454V50.7033H59.9454C65.0497 50.7033 69.1875 46.5655 69.1875 41.4612C69.1875 36.357 65.0497 32.2191 59.9454 32.2191H58.265V22.9771C58.265 17.8728 54.1272 13.735 49.0229 13.735H39.7809V12.0546C39.7809 6.95032 35.643 2.8125 30.5388 2.8125C25.4345 2.8125 21.2967 6.95032 21.2967 12.0546V13.735H12.0546C6.95032 13.735 2.8125 17.8728 2.8125 22.9771V32.2191H4.49288C9.59714 32.2191 13.735 36.357 13.735 41.4612C13.735 46.5655 9.59714 50.7033 4.49288 50.7033H2.8125V69.1875H21.2967V67.5071C21.2967 62.4029 25.4345 58.265 30.5388 58.265C35.643 58.265 39.7809 62.4029 39.7809 67.5071V69.1875H49.0229Z"
+                  stroke="#67D55E" stroke-width="5.625"/>
+        </g>
+    </g>
+    <defs>
+        <clipPath id="clip0_305_516">
+            <rect width="72" height="72" fill="white"/>
+        </clipPath>
+        <clipPath id="clip1_305_516">
+            <rect width="72" height="72" fill="white"/>
+        </clipPath>
+    </defs>
 </svg>

+ 3 - 3
src/store/index.ts

@@ -1,5 +1,5 @@
-import { createPinia } from "pinia";
+import { createPinia } from 'pinia'
 
-const store = createPinia();
+const store = createPinia()
 
-export default store;
+export default store

+ 75 - 75
src/store/modules/indexedDB.ts

@@ -1,4 +1,4 @@
-import { defineStore } from "pinia";
+import { defineStore } from 'pinia'
 
 interface IndexedDBStoreConfig {
   name: string;
@@ -15,10 +15,10 @@ interface IndexedDBConfig {
   version?: number;
 }
 
-export const useIndexedDBStore = defineStore("indexedDB", {
+export const useIndexedDBStore = defineStore('indexedDB', {
   state: () => ({
     storeRegistry: new Map<string, IndexedDBStoreConfig>(),
-    dbName: <string>"",
+    dbName: <string>'',
     db: <IDBDatabase | null>null,
     currentVersion: <number>0,
     isInitialized: <boolean>false
@@ -26,92 +26,92 @@ export const useIndexedDBStore = defineStore("indexedDB", {
   actions: {
     registerStore(storeConfig: IndexedDBStoreConfig) {
       if (!this.storeRegistry.has(storeConfig.name)) {
-        this.storeRegistry.set(storeConfig.name, storeConfig);
+        this.storeRegistry.set(storeConfig.name, storeConfig)
       }
     },
     deleteDB() {
       return new Promise<boolean>((resolve, reject) => {
-        const request = indexedDB.deleteDatabase(this.dbName);
+        const request = indexedDB.deleteDatabase(this.dbName)
         request.onsuccess = () => {
-          resolve(true);
-          window.location.reload();
-        };
+          resolve(true)
+          window.location.reload()
+        }
         request.onerror = () => {
-          reject(request.error);
-        };
-      });
+          reject(request.error)
+        }
+      })
     },
     openDB(config: IndexedDBConfig) {
       if (config) {
-        this.dbName = config.dbName;
-        this.currentVersion = config.version || 1;
+        this.dbName = config.dbName
+        this.currentVersion = config.version || 1
       }
       return new Promise((resolve, reject) => {
-        const request = indexedDB.open(this.dbName, this.currentVersion);
+        const request = indexedDB.open(this.dbName, this.currentVersion)
         request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
-          const db = (event.target as IDBOpenDBRequest).result;
+          const db = (event.target as IDBOpenDBRequest).result
           // 从注册中心获取所有Store配置
-          const stores = Array.from(this.storeRegistry.values());
+          const stores = Array.from(this.storeRegistry.values())
           stores.forEach((storeConfig: any) => {
             if (!db.objectStoreNames.contains(storeConfig.name)) {
               const objectStore = db.createObjectStore(
                 storeConfig.name,
                 { keyPath: storeConfig.keyPath }
-              );
+              )
               storeConfig.indexes?.forEach((index: any) => {
                 objectStore.createIndex(
                   index.name,
                   index.keyPath,
                   index.options
-                );
-              });
+                )
+              })
             }
-          });
-        };
+          })
+        }
 
         request.onsuccess = (event: Event) => {
-          this.db = (event.target as IDBOpenDBRequest).result;
-          this.isInitialized = true;
+          this.db = (event.target as IDBOpenDBRequest).result
+          this.isInitialized = true
           Array.from(this.db.objectStoreNames).forEach((storeName: any) => {
             this.registerStore({
               name: storeName,
-              keyPath: "id"
-            });
-          });
-          resolve(this.db);
-        };
+              keyPath: 'id'
+            })
+          })
+          resolve(this.db)
+        }
 
         request.onerror = (event: Event) => {
-          reject((event.target as IDBOpenDBRequest).error);
-        };
-      });
+          reject((event.target as IDBOpenDBRequest).error)
+        }
+      })
     },
     // 动态升级数据库版本
     async upgradeVersion() {
-      this.currentVersion += 1;
-      localStorage.setItem("dbVersion", this.currentVersion.toString());
-      this.db?.close();
-      return this.openDB({ dbName: this.dbName, version: this.currentVersion });
+      this.currentVersion += 1
+      localStorage.setItem('dbVersion', this.currentVersion.toString())
+      this.db?.close()
+      return this.openDB({ dbName: this.dbName, version: this.currentVersion })
     },
     useStore(storeName: string) {
       const verifyStore = async () => {
         if (!this.storeRegistry.has(storeName)) {
-          throw new Error(`Store ${storeName} not registered`);
+          throw new Error(`Store ${storeName} not registered`)
         }
 
         if (this.db && !this.db.objectStoreNames.contains(storeName)) {
-          await this.upgradeVersion();
+          await this.upgradeVersion()
         }
-      };
+      }
 
       const executeWithTransaction = async (mode: IDBTransactionMode, operation: any) => {
-        await verifyStore();
-        if (!this.db) await this.openDB({ dbName: this.dbName, version: this.currentVersion });
+        await verifyStore()
+        if (!this.db) await this.openDB({ dbName: this.dbName, version: this.currentVersion })
 
         return new Promise((resolve, reject) => {
           // this.db;
-          const transaction = this.db!.transaction(storeName, mode);
-          const objectStore = transaction.objectStore(storeName);
+          const transaction = this.db!.transaction(storeName, mode)
+          const objectStore = transaction.objectStore(storeName)
 
           // 事务成功完成时的回调
           // transaction.oncomplete = () => {
@@ -120,74 +120,74 @@ export const useIndexedDBStore = defineStore("indexedDB", {
 
           // 事务失败时的回调
           transaction.onerror = (event) => {
-            reject((event.target as IDBRequest).error);
-          };
+            reject((event.target as IDBRequest).error)
+          }
 
           // 执行操作
           operation(objectStore).then((result: any) => {
             // 操作成功,返回结果
-            resolve(result);
+            resolve(result)
           }).catch((error: any) => {
             // 操作失败,拒绝 Promise
-            reject(error);
-          });
-        });
-      };
+            reject(error)
+          })
+        })
+      }
 
       return {
         add: (data: any) => executeWithTransaction(
-          "readwrite",
+          'readwrite',
           (store: any) => new Promise((resolve, reject) => {
-            const request = store.add(data);
-            request.onsuccess = () => resolve(request.result as IDBValidKey);
-            request.onerror = () => reject(request.error);
+            const request = store.add(data)
+            request.onsuccess = () => resolve(request.result as IDBValidKey)
+            request.onerror = () => reject(request.error)
           })
         ),
 
         get: (key: IDBValidKey) => executeWithTransaction(
-          "readonly",
+          'readonly',
           (store: any) => new Promise((resolve, reject) => {
-            const request = store.get(key);
-            request.onsuccess = () => resolve(request.result as any);
-            request.onerror = () => reject(request.error);
+            const request = store.get(key)
+            request.onsuccess = () => resolve(request.result as any)
+            request.onerror = () => reject(request.error)
           })
         ),
 
         update: (data: any) => executeWithTransaction(
-          "readwrite",
+          'readwrite',
           (store: any) => new Promise((resolve, reject) => {
-            const request = store.put(data);
-            request.onsuccess = () => resolve(request.result as IDBValidKey);
-            request.onerror = () => reject(request.error);
+            const request = store.put(data)
+            request.onsuccess = () => resolve(request.result as IDBValidKey)
+            request.onerror = () => reject(request.error)
           })
         ),
 
         delete: (key: IDBValidKey) => executeWithTransaction(
-          "readwrite",
+          'readwrite',
           (store: any) => new Promise((resolve, reject) => {
-            const request = store.delete(key);
-            request.onsuccess = () => resolve(undefined);
-            request.onerror = () => reject(request.error);
+            const request = store.delete(key)
+            request.onsuccess = () => resolve(undefined)
+            request.onerror = () => reject(request.error)
           })
         ),
 
         getAll: () => executeWithTransaction(
-          "readonly",
+          'readonly',
           (store: any) => new Promise((resolve, reject) => {
-            const request = store.getAll();
-            request.onsuccess = () => resolve(request.result as any[]);
-            request.onerror = () => reject(request.error);
+            const request = store.getAll()
+            request.onsuccess = () => resolve(request.result as any[])
+            request.onerror = () => reject(request.error)
           })
         ),
         clearAll: () => executeWithTransaction(
-          "readwrite",
+          'readwrite',
           (store: any) => new Promise((resolve, reject) => {
-            const request = store.clear();
-            request.onsuccess = () => resolve(true);
-            request.onerror = () => reject(request.error);
+            const request = store.clear()
+            request.onsuccess = () => resolve(true)
+            request.onerror = () => reject(request.error)
           })
         )
-      };
+      }
     }
   }
-});
+})

+ 11 - 11
src/store/modules/msg.ts

@@ -1,29 +1,29 @@
-import { defineStore } from "pinia";
-import { useIndexedDBStore } from "./indexedDB";
+import { defineStore } from 'pinia'
+import { useIndexedDBStore } from './indexedDB'
 
 
-export const useMsgStore = defineStore("msg", {
+export const useMsgStore = defineStore('msg', {
   state: () => ({
-    msgUuid: <string>"",
+    msgUuid: <string>'',
     messages: <any[]>[],
     pageInfoList: []
 
   }),
   actions: {
     addMsg(msg: any) {
-      const { useStore } = useIndexedDBStore();
-      useStore(this.msgUuid).add(msg);
-      this.messages.push(msg);
+      const { useStore } = useIndexedDBStore()
+      useStore(this.msgUuid).add(msg)
+      this.messages.push(msg)
     },
 
     addMsg1(msg: any) {
-      this.messages.push(msg);
+      this.messages.push(msg)
     },
 
     msgToDB(msg: any) {
-      const { useStore } = useIndexedDBStore();
-      useStore(this.msgUuid).add(msg);
+      const { useStore } = useIndexedDBStore()
+      useStore(this.msgUuid).add(msg)
     }
 
   }
-});
+})

+ 168 - 159
src/utils/ai-service.js

@@ -1,89 +1,95 @@
-import OpenAI from 'openai';
-import hljs from 'highlight.js';
-import 'highlight.js/styles/atom-one-dark.css'; // 导入一个暗色主题样式
+import OpenAI from 'openai'
+import hljs from 'highlight.js'
+import 'highlight.js/styles/atom-one-dark.css' // 导入一个暗色主题样式
 
 export const openai = new OpenAI(
-    {
-        // 若没有配置环境变量,请用百炼API Key将下行替换为:apiKey: "sk-xxx",
-        apiKey: 'sk-e9855234f47346049809ce23ed3ebe3f',
-        baseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
-        dangerouslyAllowBrowser: true,
-    }
+  {
+    // 若没有配置环境变量,请用百炼API Key将下行替换为:apiKey: "sk-xxx",
+    apiKey: 'sk-e9855234f47346049809ce23ed3ebe3f',
+    baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
+    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) {
-    }
+  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) {
-    }
+  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://180.76.147.97:18899/test', {
-            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://180.76.147.97:18899/test', {
+      method: 'post',
+      body: JSON.stringify(data)
+    }).then(res => res.json())
+    return res
+  } catch (error) {
+
+  }
 }
+
 export async function sendMessage(message) {
-    try {
-        // 创建新的 AbortController
-        const controller = new AbortController();
-        const a = +new Date()
-        const response = await openai.chat.completions.create({
-            model: "qwen-plus",  //模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
-            messages: message,
-            stream: true
-        });
-        return response;
-    } catch (error) {
-        console.error("API call failed:", error);
-        return '[FILE]'
-    } finally {
+  try {
+    // 创建新的 AbortController
+    const controller = new AbortController()
+    const a = +new Date()
+    const response = await openai.chat.completions.create({
+      model: 'qwen-plus',  //模型列表:https://help.aliyun.com/zh/model-studio/getting-started/models
+      messages: message,
+      stream: true
+    })
+    return response
+  } catch (error) {
+    console.error('API call failed:', error)
+    return '[FILE]'
+  } finally {
 
-    }
+  }
 }
+
 function formatMessages(currentMessage, Summary, html) {
-    const messages = [{
-        role: "user",
-        content: currentMessage,
-    }]
-    // const messages = this.context.filter(msg => msg.role === 'user').map((msg) => ({
-    //     role: msg.role,
-    //     content: msg.content,
-    // }));
-    // console.log(currentMessage, this.currentPageInfo, input);
-
-    // // 如果存在页面信息,添加到当前消息的上下文
-    // if (this.currentPageInfo && !input) {
-    //     currentMessage = `基于之前总结的页面内容(标题:${JSON.stringify(this.currentPageInfo)}),${currentMessage}`;
-    // }
-    // messages.push()
-    if (Summary) return messages
-    if (html) messages.unshift({
-        role: "user",
-        content: `页面主要内容${html}`,
-    })
-    return messages
+  const messages = [{
+    role: 'user',
+    content: currentMessage
+  }]
+  // const messages = this.context.filter(msg => msg.role === 'user').map((msg) => ({
+  //     role: msg.role,
+  //     content: msg.content,
+  // }));
+  // console.log(currentMessage, this.currentPageInfo, input);
+
+  // // 如果存在页面信息,添加到当前消息的上下文
+  // if (this.currentPageInfo && !input) {
+  //     currentMessage = `基于之前总结的页面内容(标题:${JSON.stringify(this.currentPageInfo)}),${currentMessage}`;
+  // }
+  // messages.push()
+  if (Summary) return messages
+  if (html) messages.unshift({
+    role: 'user',
+    content: `页面主要内容${html}`
+  })
+  return messages
 }
+
 export function getSummaryPrompt(pageInfo) {
-    return `请帮我总结以下网页内容的要点:
+  return `请帮我总结以下网页内容的要点:
 
 页面标题:${pageInfo.title}
 网站:${pageInfo.siteName}
@@ -101,11 +107,11 @@ ${pageInfo.mainContent}
 6. 如果内容是产品介绍,需要包含主要特点和优势
 7. 返回内容做好换行,以及展示样式
 
-请以"以下是对该页面内容的总结:"开头,然后用要点的形式列出主要内容。`;
+请以"以下是对该页面内容的总结:"开头,然后用要点的形式列出主要内容。`
 }
 
-export function getFileSummaryPrompt(file,name) {
-    return `请帮我总结以下文件内容的要点:
+export function getFileSummaryPrompt(file, name) {
+  return `请帮我总结以下文件内容的要点:
 
 文件名称:${name}
 
@@ -118,95 +124,96 @@ ${file}
 3. 按重要性排序
 4. 返回内容做好换行,以及展示样式
 
-请以"以下是对该文件内容的总结:"开头,然后用要点的形式列出主要内容。`;
+请以"以下是对该文件内容的总结:"开头,然后用要点的形式列出主要内容。`
 }
+
 export function formatMessage(text) {
-    if (!text) return "";
-
-    // 用于转义代码块中的 HTML 字符
-    const escapeHtml = (str) => {
-        return str
-            .replace(/&/g, "&amp;")
-            .replace(/</g, "&lt;")
-            .replace(/>/g, "&gt;")
-            .replace(/"/g, "&quot;")
-            .replace(/'/g, "&#039;");
-    };
-
-    // 处理代码高亮
-    const highlightCode = (code, language) => {
-        if (language && language.trim() !== '') {
-            try {
-                return hljs.highlight(code, { language: language.trim() }).value;
-            } catch (e) {
-                // 如果指定的语言不支持,回退到自动检测
-                return hljs.highlightAuto(code).value;
-            }
-        }
-        return hljs.highlightAuto(code).value;
-    };
-
-    return (
-        text
-            // 处理带有语言标识的代码块
-            .replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
-                const highlightedCode = highlightCode(code, lang || '');
-                return `<pre style="background-color: #282c34; padding: 10px; border-radius: 5px; overflow-x: auto;"><code class="hljs ${lang || ''}">${highlightedCode}</code></pre>`;
-            })
-            // 处理不带语言标识的代码块
-            .replace(/```([\s\S]*?)```/g, (match, code) => {
-                const highlightedCode = highlightCode(code, '');
-                return `<pre style="background-color: #282c34; padding: 10px; border-radius: 5px; overflow-x: auto;"><code class="hljs">${highlightedCode}</code></pre>`;
-            })
-            // 处理行内代码
-            .replace(/`([^`]+)`/g, (match, code) => `<code style="background-color: #f0f0f0; padding: 2px 4px; border-radius: 3px;">${escapeHtml(code)}</code>`)
-            // 处理标题 (h1 ~ h6)
-            .replace(/^#{1,6}\s+(.+)$/gm, (match, content) => {
-                const level = match.trim().split("#").length - 1;
-                return `<h${level}>${content.trim()}</h${level}>`;
-            })
-            // 处理换行
-            .replace(/\n/g, "<br>")
-            // 处理连续空格
-            .replace(/ {2,}/g, (match) => "&nbsp;".repeat(match.length))
-            // 处理粗体
-            .replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
-            // 处理斜体
-            .replace(/\*(.*?)\*/g, "<em>$1</em>")
-            // 处理链接
-            .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank">$1</a>')
-            // 处理无序列表:先将每行列表项转换为 <li> 标签
-            .replace(/^[*-]\s+(.+)$/gm, "<li>$1</li>")
-            // 然后将连续的 <li> 包裹在 <ul> 中
-            .replace(/(<li>.*<\/li>)/gs, "<ul>$1</ul>")
-            // 处理有序列表:先将每行列表项转换为 <li> 标签
-            .replace(/^\d+\.\s+(.+)$/gm, "<li>$1</li>")
-            // 然后将连续的 <li> 包裹在 <ol> 中
-            .replace(/(<li>.*<\/li>)/gs, "<ol>$1</ol>")
-            // 处理分隔线
-            .replace(/^---+$/gm, "<hr>")
-            // 处理引用
-            .replace(/^>\s+(.+)$/gm, "<blockquote>$1</blockquote>")
-    );
+  if (!text) return ''
+
+  // 用于转义代码块中的 HTML 字符
+  const escapeHtml = (str) => {
+    return str
+      .replace(/&/g, '&amp;')
+      .replace(/</g, '&lt;')
+      .replace(/>/g, '&gt;')
+      .replace(/"/g, '&quot;')
+      .replace(/'/g, '&#039;')
+  }
+
+  // 处理代码高亮
+  const highlightCode = (code, language) => {
+    if (language && language.trim() !== '') {
+      try {
+        return hljs.highlight(code, { language: language.trim() }).value
+      } catch (e) {
+        // 如果指定的语言不支持,回退到自动检测
+        return hljs.highlightAuto(code).value
+      }
+    }
+    return hljs.highlightAuto(code).value
+  }
+
+  return (
+    text
+      // 处理带有语言标识的代码块
+      .replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
+        const highlightedCode = highlightCode(code, lang || '')
+        return `<pre style="background-color: #282c34; padding: 10px; border-radius: 5px; overflow-x: auto;"><code class="hljs ${lang || ''}">${highlightedCode}</code></pre>`
+      })
+      // 处理不带语言标识的代码块
+      .replace(/```([\s\S]*?)```/g, (match, code) => {
+        const highlightedCode = highlightCode(code, '')
+        return `<pre style="background-color: #282c34; padding: 10px; border-radius: 5px; overflow-x: auto;"><code class="hljs">${highlightedCode}</code></pre>`
+      })
+      // 处理行内代码
+      .replace(/`([^`]+)`/g, (match, code) => `<code style="background-color: #f0f0f0; padding: 2px 4px; border-radius: 3px;">${escapeHtml(code)}</code>`)
+      // 处理标题 (h1 ~ h6)
+      .replace(/^#{1,6}\s+(.+)$/gm, (match, content) => {
+        const level = match.trim().split('#').length - 1
+        return `<h${level}>${content.trim()}</h${level}>`
+      })
+      // 处理换行
+      .replace(/\n/g, '<br>')
+      // 处理连续空格
+      .replace(/ {2,}/g, (match) => '&nbsp;'.repeat(match.length))
+      // 处理粗体
+      .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
+      // 处理斜体
+      .replace(/\*(.*?)\*/g, '<em>$1</em>')
+      // 处理链接
+      .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank">$1</a>')
+      // 处理无序列表:先将每行列表项转换为 <li> 标签
+      .replace(/^[*-]\s+(.+)$/gm, '<li>$1</li>')
+      // 然后将连续的 <li> 包裹在 <ul> 中
+      .replace(/(<li>.*<\/li>)/gs, '<ul>$1</ul>')
+      // 处理有序列表:先将每行列表项转换为 <li> 标签
+      .replace(/^\d+\.\s+(.+)$/gm, '<li>$1</li>')
+      // 然后将连续的 <li> 包裹在 <ol> 中
+      .replace(/(<li>.*<\/li>)/gs, '<ol>$1</ol>')
+      // 处理分隔线
+      .replace(/^---+$/gm, '<hr>')
+      // 处理引用
+      .replace(/^>\s+(.+)$/gm, '<blockquote>$1</blockquote>')
+  )
 }
 
 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);
-    // data[0].forEach((header, i) => {
-    //     if (!this.excelData[header]) this.excelData[header] = []
-    //     this.excelData[header].push(data[1][i])
-    // })
+  // 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])
+  // })
 
-    return `我将向你展示一个通过SheetJS库读取的Excel文件内容和一个form表单。请帮我理解这些数据:
+  return `我将向你展示一个通过SheetJS库读取的Excel文件内容和一个form表单。请帮我理解这些数据:
 
 文件名:${fileName}
-列标题:${data.join(", ")}
+列标题:${data.join(', ')}
 
 表单内容:
 ${pageInfo}
@@ -219,11 +226,12 @@ ${pageInfo}
 4. 通过type字段告诉我输入项的类型
 5. 仅返回数组,不要返回任何其他内容。`
 }
+
 // 5. 如果表单项有label标签,同时返回label, 通过label字段告诉我label元素的文本
-export function buildObjPrompt(obj,  pageInfo) {
-  
+export function buildObjPrompt(obj, pageInfo) {
 
-    return `我将向你展示一个对象和一个form表单。请帮我理解这些数据:
+
+  return `我将向你展示一个对象和一个form表单。请帮我理解这些数据:
 
 对象:${JSON.stringify(obj)}
 表单内容:
@@ -237,8 +245,9 @@ ${pageInfo}
 5. 通过type字段告诉我输入项的类型,如果对象中key对应的是日期,type统一返回date
 6. 仅返回数组,不要返回任何其他内容。`
 }
+
 function escapeHtml(html) {
-    const div = document.createElement("div");
-    div.textContent = html;
-    return div.innerHTML;
+  const div = document.createElement('div')
+  div.textContent = html
+  return div.innerHTML
 }

+ 19 - 19
src/utils/dynamicTime.js

@@ -1,25 +1,25 @@
-import {ref, onMounted, onUnmounted} from 'vue';
-import moment from "moment";
+import { ref, onMounted, onUnmounted } from 'vue'
+import moment from 'moment'
 
 const dd = [
-    {value: 'Monday', label: '星期一'},
-    {value: 'Tuesday', label: '星期二'},
-    {value: 'Wednesday', label: '星期三'},
-    {value: 'Thursday', label: '星期四'},
-    {value: 'Friday', label: '星期五'},
-    {value: 'Saturday', label: '星期六'},
-    {value: 'Sunday', label: '星期日'}
+  { value: 'Monday', label: '星期一' },
+  { value: 'Tuesday', label: '星期二' },
+  { value: 'Wednesday', label: '星期三' },
+  { value: 'Thursday', label: '星期四' },
+  { value: 'Friday', label: '星期五' },
+  { value: 'Saturday', label: '星期六' },
+  { value: 'Sunday', label: '星期日' }
 ]
 
 export function useTime(format = 'HH:mm:ss') {
-    const interval = ref(null);
-    const globalTime = ref(null);
-    onMounted(() => interval.value = setInterval(() => {
-        const l = dd.find(e => {
-            return e.value === moment(new Date()).format('dddd')
-        }).label;
-        globalTime.value = moment(new Date()).format('YYYY年MM月DD日 ') + l + moment(new Date()).format(format);
-    }, 1000))
-    onUnmounted(() => clearInterval(interval.value))
-    return globalTime;
+  const interval = ref(null)
+  const globalTime = ref(null)
+  onMounted(() => interval.value = setInterval(() => {
+    const l = dd.find(e => {
+      return e.value === moment(new Date()).format('dddd')
+    }).label
+    globalTime.value = moment(new Date()).format('YYYY年MM月DD日 ') + l + moment(new Date()).format(format)
+  }, 1000))
+  onUnmounted(() => clearInterval(interval.value))
+  return globalTime
 }

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

@@ -1,7 +1,7 @@
 // 确保类定义在全局作用域
 export default class PageAnalyzer {
   constructor() {
-    this.readability = null;
+    this.readability = null
   }
 
   /**
@@ -11,36 +11,36 @@ export default class PageAnalyzer {
   analyzePage(form = false) {
     try {
       // 检查Readability是否可用
-      if (typeof Readability === "undefined") {
+      if (typeof Readability === 'undefined') {
         console.warn(
-          "Readability not loaded, falling back to basic extraction"
-        );
-        return this.fallbackAnalysis(form);
+          'Readability not loaded, falling back to basic extraction'
+        )
+        return this.fallbackAnalysis(form)
       }
 
       // 创建文档副本以避免修改原始DOM
-      const documentClone = document.cloneNode(true);
+      const documentClone = document.cloneNode(true)
 
       // 初始化 Readability
       this.readability = new Readability(documentClone, {
         debug: false,
-        charThreshold: 20,
-      });
+        charThreshold: 20
+      })
 
       // 解析页面
-      const article = this.readability.parse();
+      const article = this.readability.parse()
 
       return {
         title: article.title || document.title,
         url: window.location.href,
-        mainContent: article.textContent || article.excerpt || "",
-        excerpt: article.excerpt || "",
+        mainContent: article.textContent || article.excerpt || '',
+        excerpt: article.excerpt || '',
         siteName: article.siteName || new URL(window.location.href).hostname,
-        wordCount: article.length || 0,
-      };
+        wordCount: article.length || 0
+      }
     } catch (error) {
-      console.warn("Readability failed, using fallback:", error);
-      return this.fallbackAnalysis();
+      console.warn('Readability failed, using fallback:', error)
+      return this.fallbackAnalysis()
     }
   }
 
@@ -50,10 +50,10 @@ export default class PageAnalyzer {
       title: document.title,
       url: window.location.href,
       mainContent: this.extractMainContent(iframe),
-      excerpt: "",
+      excerpt: '',
       siteName: new URL(window.location.href).hostname,
-      wordCount: 0,
-    };
+      wordCount: 0
+    }
   }
 
   // 基础的内容提取方法
@@ -62,49 +62,49 @@ export default class PageAnalyzer {
 
     //提取页面的表单
     if (iframe) {
-      const form = document.querySelector("form");
+      const form = document.querySelector('form')
       if (form) {
-        content.textContent = form.outerHTML;
+        content.textContent = form.outerHTML
       }
     } else {
-      const content = document.body.cloneNode(true);
+      const content = document.body.cloneNode(true)
       return cleanPage(content)
       // .trim().replace(/\s+/g, " ")
       // content
       //     .querySelectorAll("script, style, iframe, nav, header, footer,svg")
       //     .forEach((el) => el.remove());
 
-      
+
     }
 
 
   }
 };
 
-export  function cleanPage(body) {
+export function cleanPage(body) {
 
   // 移除所有行内样式
-  const elementsWithInlineStyle = body.querySelectorAll('[style]');
+  const elementsWithInlineStyle = body.querySelectorAll('[style]')
   elementsWithInlineStyle.forEach(element => {
-    element.removeAttribute('style');
-  });
+    element.removeAttribute('style')
+  })
 
   // 移除所有注释节点
-  const comments = [];
-  const walk = document.createTreeWalker(body, NodeFilter.SHOW_COMMENT, null, false);
+  const comments = []
+  const walk = document.createTreeWalker(body, NodeFilter.SHOW_COMMENT, null, false)
   while (walk.nextNode()) {
-    comments.push(walk.currentNode);
+    comments.push(walk.currentNode)
   }
-  comments.forEach(comment => comment.remove());
+  comments.forEach(comment => comment.remove())
 
   // 移除所有SVG图标
-  body.querySelectorAll("script, style, iframe, nav, header, footer,svg").forEach(svg => svg.remove());
+  body.querySelectorAll('script, style, iframe, nav, header, footer,svg').forEach(svg => svg.remove())
 
   // 移除所有图片的src属性
-  const images = body.querySelectorAll('img');
+  const images = body.querySelectorAll('img')
   images.forEach(img => {
-    img.removeAttribute('src');
-  });
+    img.removeAttribute('src')
+  })
 
   // 可选择移除其他无关内容,比如脚本和广告等
   // const scripts = body.querySelectorAll('script');
@@ -113,61 +113,62 @@ export  function cleanPage(body) {
   // const iframes = body.querySelectorAll('iframe');
   // iframes.forEach(iframe => iframe.remove());
 
-  const ads = body.querySelectorAll('.ad, .advertisement, .ads');
-  ads.forEach(ad => ad.remove());
+  const ads = body.querySelectorAll('.ad, .advertisement, .ads')
+  ads.forEach(ad => ad.remove())
 
-  const regex = /\s+/g;
+  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 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;
+  const temp = document.createElement('div')
+  temp.innerHTML = body.outerHTML
+
   // 递归删除空标签
   function removeEmpty(element) {
-    const children = Array.from(element.children);
+    const children = Array.from(element.children)
     children.forEach(child => {
-      removeEmpty(child); // 递归处理子元素
-    });
+      removeEmpty(child) // 递归处理子元素
+    })
 
     // 检查标签是否为空
     if (!element.innerHTML.trim()) {
-      element.remove(); // 删除空标签
+      element.remove() // 删除空标签
     }
   }
 
   // 从临时容器的子元素开始处理
-  removeEmpty(temp);
+  removeEmpty(temp)
 
   // 删除 <link> 标签
-  const linkTags = temp.querySelectorAll('link');
+  const linkTags = temp.querySelectorAll('link')
   linkTags.forEach(link => {
-    link.remove();
-  });
+    link.remove()
+  })
 
   // 遍历所有元素
-  const elements = temp.querySelectorAll('*');
+  const elements = temp.querySelectorAll('*')
   elements.forEach(element => {
     // 获取所有属性
-    const attributes = Array.from(element.attributes);
+    const attributes = Array.from(element.attributes)
     attributes.forEach(attr => {
       // 如果属性不是标准属性,则移除
       if (!standardAttributes.has(attr.name) && !attr.name.startsWith('aria-')) {
-        element.removeAttribute(attr.name);
+        element.removeAttribute(attr.name)
       }
-    });
-  });
+    })
+  })
 
   // 获取处理后的 HTML 字符串
-  const cleanedHtml = temp.innerHTML.trim().replace(regex, " ");
+  const cleanedHtml = temp.innerHTML.trim().replace(regex, ' ')
 
   // 销毁临时容器
-  temp.remove();
+  temp.remove()
 
   console.log(cleanedHtml)
   // content.outerHTML.trim().replace(/\s+/g, " ");
-  return cleanedHtml;
+  return cleanedHtml
 }
 
 

+ 8 - 8
src/utils/rem.js

@@ -1,14 +1,14 @@
 /** 设置 rem 函数 */
 function setRem() {
-    console.log(222223)
-    const htmlWidth = document.documentElement.clientWidth || document.body.clientWidth;
-    const htmlDom = document.getElementsByTagName('html')[0];
-    console.log(htmlWidth,htmlDom.style.fontSize)
-    htmlDom.style.fontSize = htmlWidth / 100 + 'px';
+  console.log(222223)
+  const htmlWidth = document.documentElement.clientWidth || document.body.clientWidth
+  const htmlDom = document.getElementsByTagName('html')[0]
+  console.log(htmlWidth, htmlDom.style.fontSize)
+  htmlDom.style.fontSize = htmlWidth / 100 + 'px'
 }
 
-setRem();
+setRem()
 
 window.onresize = function() {
-    setRem();
-};
+  setRem()
+}

+ 52 - 52
src/utils/request.js

@@ -1,23 +1,23 @@
-import axios, { CancelToken, isCancel } from 'axios';
-import { ElMessage, ElNotification } from 'element-plus';
-import errorCode from './errorCode.js';
+import axios, { CancelToken, isCancel } from 'axios'
+import { ElMessage, ElNotification } from 'element-plus'
+import errorCode from './errorCode.js'
 
-axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
 // 创建axios实例
 const service = axios.create({
   // axios中请求配置有baseURL选项,表示请求URL公共部分
   baseURL: import.meta.env.VITE_APP_BASE_API,
   // 超时
-  timeout: 60000,
-});
-let cancel;
+  timeout: 60000
+})
+let cancel
 // request拦截器
 service.interceptors.request.use(config => {
   // console.log(config)
-  if (cancel) cancel('取消了');
+  if (cancel) cancel('取消了')
   if (config.cancel) {
     config.cancelToken = new CancelToken((c) => { //c是一个函数,调用c就可以关闭本次请求
-      cancel = c;
+      cancel = c
     })
   }
   // // 是否需要设置 token
@@ -26,7 +26,7 @@ service.interceptors.request.use(config => {
   // const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
   let token = sessionStorage.getItem('token')
   if (token) {
-    config.headers['Authorization'] = "Bearer " + token // 让每个请求携带自定义token 请根据实际情况自行修改
+    config.headers['Authorization'] = 'Bearer ' + token // 让每个请求携带自定义token 请根据实际情况自行修改
   }
   // get请求映射params参数
   // if (config.method === 'get' && config.params) {
@@ -65,53 +65,53 @@ service.interceptors.request.use(config => {
 
 // 响应拦截器
 service.interceptors.response.use(res => {
-  // 未设置状态码则默认成功状态
-  const code = res.data.code || 200;
-  // 获取错误信息
-  const msg = errorCode[code] || res.data.msg || errorCode['default']
-  // 二进制数据则直接返回
-  if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
-    let filename = res.headers['content-disposition'].split('filename=')[1];
-    return { fileName: filename, data: res.data };
-  }
-  if (code === 401) {
+    // 未设置状态码则默认成功状态
+    const code = res.data.code || 200
+    // 获取错误信息
+    const msg = errorCode[code] || res.data.msg || errorCode['default']
+    // 二进制数据则直接返回
+    if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
+      let filename = res.headers['content-disposition'].split('filename=')[1]
+      return { fileName: filename, data: res.data }
+    }
+    if (code === 401) {
 
-    // if (!isRelogin.show) {
-    //   isRelogin.show = true;
-    //   ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
-    //     isRelogin.show = false;
-    //     useUserStore().logOut().then(() => {
-    //       location.href = '/index';
-    //     })
-    //   }).catch(() => {
-    //     isRelogin.show = false;
-    //   });
-    // }
-    return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
-  } else if (code === 500) {
-    ElMessage({ message: msg, type: 'error', grouping: true })
-    return Promise.reject(msg)
-  } else if (code === 601) {
-    ElMessage({ message: msg, type: 'warning', grouping: true })
-    return Promise.reject(new Error(msg))
-  } else if (code !== 200) {
-    ElNotification.error({ title: msg })
-    return Promise.reject('error')
-  } else {
-    return Promise.resolve(res.data)
-  }
-},
+      // if (!isRelogin.show) {
+      //   isRelogin.show = true;
+      //   ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
+      //     isRelogin.show = false;
+      //     useUserStore().logOut().then(() => {
+      //       location.href = '/index';
+      //     })
+      //   }).catch(() => {
+      //     isRelogin.show = false;
+      //   });
+      // }
+      return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
+    } else if (code === 500) {
+      ElMessage({ message: msg, type: 'error', grouping: true })
+      return Promise.reject(msg)
+    } else if (code === 601) {
+      ElMessage({ message: msg, type: 'warning', grouping: true })
+      return Promise.reject(new Error(msg))
+    } else if (code !== 200) {
+      ElNotification.error({ title: msg })
+      return Promise.reject('error')
+    } else {
+      return Promise.resolve(res.data)
+    }
+  },
   error => {
     if (isCancel(error)) {
       // console.log('用户取消')
     } else {
-      let { message } = error;
-      if (message === "Network Error") {
-        message = "后端接口连接异常";
-      } else if (message.includes("timeout")) {
-        message = "系统接口请求超时";
-      } else if (message.includes("Request failed with status code")) {
-        message = "系统接口" + message.substr(message.length - 3) + "异常";
+      let { message } = error
+      if (message === 'Network Error') {
+        message = '后端接口连接异常'
+      } else if (message.includes('timeout')) {
+        message = '系统接口请求超时'
+      } else if (message.includes('Request failed with status code')) {
+        message = '系统接口' + message.substr(message.length - 3) + '异常'
       }
       ElMessage({ message: message, type: 'error', duration: 5 * 1000, grouping: true })
       return Promise.reject(error)

+ 2 - 2
tailwind.config.js

@@ -2,8 +2,8 @@
 export default {
   content: ['./src/**/*.{vue,js,ts,html}'],
   theme: {
-    extend: {},
+    extend: {}
   },
-  plugins: [],
+  plugins: []
 }
 

+ 2 - 2
tsconfig.json

@@ -1,6 +1,6 @@
 {
   "extends": "./.wxt/tsconfig.json",
   "compilerOptions": {
-    "jsx": "preserve",
-  },
+    "jsx": "preserve"
+  }
 }

+ 19 - 19
wxt.config.ts

@@ -1,28 +1,28 @@
-import { defineConfig } from 'wxt';
+import { defineConfig } from 'wxt'
 
 // See https://wxt.dev/api/config.html
 export default defineConfig({
   extensionApi: 'chrome',
-  srcDir: "src",
+  srcDir: 'src',
   manifest: {
-    "name": "派维斯智能体助手",
-    "version": "0.1.7",
-    "permissions": [
-      "storage",
-      "history",
-      "tabs",
-      "activeTab",
-      "webNavigation",
-      "webRequest",
-      "sidePanel"
+    'name': '派维斯智能体助手',
+    'version': '0.1.7',
+    'permissions': [
+      'storage',
+      'history',
+      'tabs',
+      'activeTab',
+      'webNavigation',
+      'webRequest',
+      'sidePanel'
     ],
-    "content_security_policy": {
-      "extension_pages": "script-src 'self'; object-src 'self';"
+    'content_security_policy': {
+      'extension_pages': 'script-src \'self\'; object-src \'self\';'
     },
-    "action": {
-      "default_title": "派维斯智能体助手",
+    'action': {
+      'default_title': '派维斯智能体助手'
     },
-    "options_page": "options.html",
+    'options_page': 'options.html'
   },
-  modules: ['@wxt-dev/module-vue'],
-});
+  modules: ['@wxt-dev/module-vue']
+})

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio