mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 21:13:50 +00:00
feat(chatbot-extension): a Chrome extension that can be using for chat with AI on any website (#2235)
* feat(chatbot-extension): a Chrome extension that can be using for chat with AI on any website * fix: 插件支持语音输入 feat:chatbot支持切换 * fix: 切换chatbot后,自动隐藏bot列表
This commit is contained in:
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 1012 B |
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "ChatBot Extension",
|
||||
"version": "1.1",
|
||||
"description": "A ChatBot",
|
||||
"permissions": [
|
||||
"storage",
|
||||
"notifications",
|
||||
"tabs",
|
||||
"activeTab",
|
||||
"scripting",
|
||||
"webRequest"
|
||||
],
|
||||
"host_permissions": [
|
||||
"<all_urls>"
|
||||
],
|
||||
"background": {
|
||||
"service_worker": "src/background.js"
|
||||
},
|
||||
"action": {
|
||||
"default_popup": "src/popup.html",
|
||||
"default_icon": {
|
||||
"16": "img/favicon32.png",
|
||||
"48": "img/favicon32.png",
|
||||
"128": "img/favicon32.png"
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"16": "img/favicon32.png",
|
||||
"32": "img/favicon32.png",
|
||||
"48": "img/favicon32.png",
|
||||
"128": "img/favicon32.png"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"js": [
|
||||
"src/content.js"
|
||||
],
|
||||
"matches": ["<all_urls>"]
|
||||
}
|
||||
]
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
let requestInterceptor = null;
|
||||
|
||||
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
|
||||
if (message.action === "startRequestInterception") {
|
||||
const botSrc = message.chatbotSrc;
|
||||
console.log("src", botSrc);
|
||||
const urlObj = new URL(botSrc);
|
||||
const domain = urlObj.host;
|
||||
const searchParams = urlObj.searchParams;
|
||||
const frameShareId = searchParams.get('shareId') || '';
|
||||
let frameChatId = searchParams.get('chatId') || '';
|
||||
|
||||
// 移除已有的拦截器(如果存在)
|
||||
if (requestInterceptor) {
|
||||
chrome.webRequest.onBeforeRequest.removeListener(requestInterceptor);
|
||||
}
|
||||
|
||||
requestInterceptor = function (details) {
|
||||
if (details.frameId !== -1
|
||||
&& details.url.includes(domain)
|
||||
&& details.url.includes("chat/completions")) {
|
||||
console.log("Intercepted request from chatbot-iframe:", details);
|
||||
if (details.requestBody.raw) {
|
||||
let decoder = new TextDecoder("utf-8");
|
||||
let postData = decoder.decode(new Uint8Array(details.requestBody.raw[0].bytes));
|
||||
try {
|
||||
let postDataObj = JSON.parse(postData);
|
||||
let shareId = postDataObj.shareId;
|
||||
let chatId = postDataObj.chatId;
|
||||
|
||||
if (frameChatId !== chatId && frameShareId === shareId) {
|
||||
chrome.storage.local.set({["shareId"]: shareId});
|
||||
chrome.storage.local.set({["chatId"]: chatId});
|
||||
frameChatId = chatId;
|
||||
console.log(`Stored shareId: ${shareId} and chatId: ${chatId} to localStorage.`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error parsing postData:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
chrome.webRequest.onBeforeRequest.addListener(
|
||||
requestInterceptor,
|
||||
{ urls: ["<all_urls>"] },
|
||||
["requestBody"]
|
||||
);
|
||||
}
|
||||
});
|
@@ -0,0 +1,533 @@
|
||||
chrome.storage.local.get(["showChatBot"], function (result) {
|
||||
if (result.showChatBot === undefined || result.showChatBot) {
|
||||
const chatBtnId = 'fastgpt-chatbot-button';
|
||||
const chatWindowId = 'fastgpt-chatbot-window';
|
||||
const chatWindowWrapperId = 'fastgpt-chatbot-wrapper';
|
||||
const defaultOpen = false;
|
||||
const canDrag = true;
|
||||
const MessageIcon =
|
||||
`data:image/svg+xml;base64,PHN2ZyB0PSIxNjkwNTMyNzg1NjY0IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjQxMzIiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48cGF0aCBkPSJNNTEyIDMyQzI0Ny4wNCAzMiAzMiAyMjQgMzIgNDY0QTQxMC4yNCA0MTAuMjQgMCAwIDAgMTcyLjQ4IDc2OEwxNjAgOTY1LjEyYTI1LjI4IDI1LjI4IDAgMCAwIDM5LjA0IDIyLjRsMTY4LTExMkE1MjguNjQgNTI4LjY0IDAgMCAwIDUxMiA4OTZjMjY0Ljk2IDAgNDgwLTE5MiA0ODAtNDMyUzc3Ni45NiAzMiA1MTIgMzJ6IG0yNDQuOCA0MTZsLTM2MS42IDMwMS43NmExMi40OCAxMi40OCAwIDAgMS0xOS44NC0xMi40OGw1OS4yLTIzMy45MmgtMTYwYTEyLjQ4IDEyLjQ4IDAgMCAxLTcuMzYtMjMuMzZsMzYxLjYtMzAxLjc2YTEyLjQ4IDEyLjQ4IDAgMCAxIDE5Ljg0IDEyLjQ4bC01OS4yIDIzMy45MmgxNjBhMTIuNDggMTIuNDggMCAwIDEgOCAyMi4wOHoiIGZpbGw9IiM0ZTgzZmQiIHAtaWQ9IjQxMzMiPjwvcGF0aD48L3N2Zz4=`;
|
||||
const CloseIcon =
|
||||
'data:image/svg+xml;base64,PHN2ZyB0PSIxNjkwNTM1NDQxNTI2IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjYzNjciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48cGF0aCBkPSJNNTEyIDEwMjRBNTEyIDUxMiAwIDEgMSA1MTIgMGE1MTIgNTEyIDAgMCAxIDAgMTAyNHpNMzA1Ljk1NjU3MSAzNzAuMzk1NDI5TDQ0Ny40ODggNTEyIDMwNS45NTY1NzEgNjUzLjYwNDU3MWE0NS41NjggNDUuNTY4IDAgMSAwIDY0LjQzODg1OCA2NC40Mzg4NThMNTEyIDU3Ni41MTJsMTQxLjYwNDU3MSAxNDEuNTMxNDI5YTQ1LjU2OCA0NS41NjggMCAwIDAgNjQuNDM4ODU4LTY0LjQzODg1OEw1NzYuNTEyIDUxMmwxNDEuNTMxNDI5LTE0MS42MDQ1NzFhNDUuNTY4IDQ1LjU2OCAwIDEgMC02NC40Mzg4NTgtNjQuNDM4ODU4TDUxMiA0NDcuNDg4IDM3MC4zOTU0MjkgMzA1Ljk1NjU3MWE0NS41NjggNDUuNTY4IDAgMCAwLTY0LjQzODg1OCA2NC40Mzg4NTh6IiBmaWxsPSIjNGU4M2ZkIiBwLWlkPSI2MzY4Ij48L3BhdGg+PC9zdmc+';
|
||||
const FullscreenIcon =
|
||||
'data:image/png;base64,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';
|
||||
const SwitchIcon =
|
||||
'data:image/png;base64,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';
|
||||
const ChatBtn = document.createElement('div');
|
||||
ChatBtn.id = chatBtnId;
|
||||
ChatBtn.style.cssText =
|
||||
'position: fixed; bottom: 30px; right: 60px; width: 40px; height: 40px; cursor: pointer; z-index: 2147483647; transition: 0;';
|
||||
|
||||
const ChatBtnDiv = document.createElement('img');
|
||||
ChatBtnDiv.src = defaultOpen ? CloseIcon : MessageIcon;
|
||||
ChatBtnDiv.setAttribute('width', '100%');
|
||||
ChatBtnDiv.setAttribute('height', '100%');
|
||||
ChatBtnDiv.draggable = false;
|
||||
|
||||
const iframeWrapper = document.createElement('div');
|
||||
iframeWrapper.id = chatWindowWrapperId;
|
||||
iframeWrapper.style.cssText =
|
||||
'border: none; position: fixed; flex-direction: column; justify-content: space-between; box-shadow: rgba(150, 150, 150, 0.2) 0px 10px 30px 0px, rgba(150, 150, 150, 0.2) 0px 0px 0px 1px; bottom: 80px; right: 60px; max-width: 90vw; min-width: 10vw; max-height: 85vh; min-height: 15vh; border-radius: 0.75rem; display: flex; z-index: 2147483647; overflow: hidden; left: unset; background-color: #F3F4F6;';
|
||||
iframeWrapper.style.visibility = defaultOpen ? 'unset' : 'hidden';
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.referrerPolicy = 'no-referrer';
|
||||
iframe.allow = 'microphone';
|
||||
iframe.title = 'FastGPT Chat Window';
|
||||
iframe.id = chatWindowId;
|
||||
iframe.style.cssText = 'border: none; width: 100%; height: 100%;';
|
||||
|
||||
iframeWrapper.appendChild(iframe);
|
||||
|
||||
const fullscreenBtn = document.createElement('img');
|
||||
fullscreenBtn.src = FullscreenIcon;
|
||||
fullscreenBtn.style.position = 'absolute';
|
||||
fullscreenBtn.style.background = 'none';
|
||||
fullscreenBtn.style.border = 'none';
|
||||
fullscreenBtn.style.cursor = 'pointer';
|
||||
fullscreenBtn.id = 'fullscreenBtn';
|
||||
fullscreenBtn.style.width = '35px';
|
||||
|
||||
fullscreenBtn.addEventListener('click', function () {
|
||||
const botSrc = iframe.src;
|
||||
if (botSrc) {
|
||||
window.open(botSrc, '_blank');
|
||||
}
|
||||
});
|
||||
|
||||
const switchBtn = document.createElement('img');
|
||||
switchBtn.src = SwitchIcon;
|
||||
switchBtn.style.position = 'absolute';
|
||||
switchBtn.style.background = 'none';
|
||||
switchBtn.style.border = 'none';
|
||||
switchBtn.style.cursor = 'pointer';
|
||||
switchBtn.id = 'switchBtn';
|
||||
switchBtn.style.width = '35px';
|
||||
|
||||
switchBtn.addEventListener('click', function () {
|
||||
chrome.storage.local.get(["configs", "chatbotSrc",], function (result) {
|
||||
const configs = result.configs || [];
|
||||
// 创建或更新列表容器
|
||||
let listWrapper = document.getElementById('configList');
|
||||
if (listWrapper) {
|
||||
iframeWrapper.removeChild(listWrapper);
|
||||
return;
|
||||
}
|
||||
listWrapper = document.createElement('div');
|
||||
listWrapper.id = 'configList';
|
||||
listWrapper.className = 'ant-dropdown-menu';
|
||||
listWrapper.style.position = 'absolute';
|
||||
listWrapper.style.zIndex = '2147483647';
|
||||
listWrapper.style.backgroundColor = '#fff';
|
||||
listWrapper.style.border = '1px solid #ccc';
|
||||
listWrapper.style.borderRadius = '4px';
|
||||
listWrapper.classList.add('ant-dropdown', 'ant-dropdown-placement-bottomRight');
|
||||
const switchBtnRect = switchBtn.getBoundingClientRect();
|
||||
const iframeWrapperRect = iframeWrapper.getBoundingClientRect();
|
||||
const switchBtnOffsetRight = iframeWrapperRect.right - switchBtnRect.right;
|
||||
const switchBtnOffsetTop = switchBtnRect.top - iframeWrapperRect.top;
|
||||
// 确保listWrapper存在并调整其位置
|
||||
listWrapper.style.right = switchBtnOffsetRight + 'px';
|
||||
listWrapper.style.top = (switchBtnOffsetTop + switchBtn.offsetHeight) + 'px';
|
||||
listWrapper.style.padding = '5px';
|
||||
// 显示所有chatbot名称
|
||||
configs.forEach((config) => {
|
||||
const item = document.createElement('div');
|
||||
item.textContent = config.name;
|
||||
item.className = 'ant-dropdown-menu-item'; // 使用 Ant Design 的类名
|
||||
item.style.cursor = 'pointer';
|
||||
item.style.padding = '5px 16px';
|
||||
item.style.borderRadius = '4px';
|
||||
// 设置默认样式
|
||||
item.style.position = 'relative';
|
||||
item.style.lineHeight = '22px';
|
||||
item.style.color = '#606266';
|
||||
item.style.fontSize = '14px';
|
||||
item.style.whiteSpace = 'nowrap';
|
||||
item.style.textAlign = 'left';
|
||||
item.style.boxSizing = 'border-box';
|
||||
item.style.background = '#fff';
|
||||
item.style.borderBottomColor = '#e8eaec';
|
||||
item.style.borderBottomStyle = 'solid';
|
||||
item.style.borderBottomWidth = '1px';
|
||||
|
||||
// 设置选中样式
|
||||
if (config.url === result.chatbotSrc) {
|
||||
item.style.color = '#1890ff';
|
||||
item.style.fontWeight = 'bold';
|
||||
item.style.background = '#e6f7ff';
|
||||
}
|
||||
|
||||
// 为每个列表项添加点击事件监听器
|
||||
item.addEventListener('click', function () {
|
||||
// 更新样式,移除其他项的蓝色
|
||||
const items = listWrapper.querySelectorAll('.ant-dropdown-menu-item');
|
||||
items.forEach((i) => {
|
||||
i.style.color = '#606266';
|
||||
i.style.fontWeight = 'normal';
|
||||
i.style.background = '#fff';
|
||||
});
|
||||
// 设置当前项为蓝色
|
||||
item.style.color = '#1890ff';
|
||||
item.style.fontWeight = 'bold';
|
||||
item.style.background = '#e6f7ff';
|
||||
|
||||
// 更新chatbotSrc的值
|
||||
chrome.storage.local.set({chatbotSrc: config.url}, function () {
|
||||
console.log('Updated chatbotSrc:', config.url);
|
||||
});
|
||||
|
||||
// 更新iframe的src
|
||||
loadChatBotIframe(document.getElementById(chatWindowWrapperId));
|
||||
});
|
||||
|
||||
listWrapper.appendChild(item);
|
||||
});
|
||||
|
||||
// 将列表容器添加到body中或确保它已经存在
|
||||
if (!iframeWrapper.contains(listWrapper)) {
|
||||
iframeWrapper.appendChild(listWrapper);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.body.appendChild(iframeWrapper);
|
||||
|
||||
let chatBtnDragged = false;
|
||||
let chatBtnDown = false;
|
||||
let chatBtnMouseX;
|
||||
let chatBtnMouseY;
|
||||
|
||||
ChatBtn.addEventListener('click', function () {
|
||||
if (chatBtnDragged) {
|
||||
chatBtnDragged = false;
|
||||
return;
|
||||
}
|
||||
const chatWindow = document.getElementById(chatWindowWrapperId);
|
||||
if (!chatWindow) return;
|
||||
|
||||
const visibilityVal = chatWindow.style.visibility;
|
||||
if (visibilityVal === 'hidden') {
|
||||
ChatBtnDiv.src = CloseIcon;
|
||||
loadChatBotIframe(chatWindow);
|
||||
} else {
|
||||
chatWindow.style.visibility = 'hidden';
|
||||
const tmpBtn = document.getElementById('fullscreenBtn');
|
||||
const tmpBtn1 = document.getElementById('switchBtn');
|
||||
const tmpEl = document.getElementById('configList');
|
||||
if (tmpBtn) {
|
||||
chatWindow.removeChild(tmpBtn);
|
||||
}
|
||||
if (tmpBtn1) {
|
||||
chatWindow.removeChild(tmpBtn1);
|
||||
}
|
||||
if (tmpEl) {
|
||||
chatWindow.removeChild(tmpEl);
|
||||
}
|
||||
ChatBtnDiv.src = MessageIcon;
|
||||
}
|
||||
});
|
||||
|
||||
function loadChatBotIframe(chatWindow) {
|
||||
chrome.storage.local.get(["chatbotSrc", "shareId", "chatId", "fastUID", "chatBotWidth", "chatBotHeight"], function (result) {
|
||||
let botSrc = result.chatbotSrc;
|
||||
if (!botSrc || botSrc === 'about:blank' || botSrc === '') {
|
||||
console.log("Can't find botSrc");
|
||||
iframe.src = 'data:text/html;charset=utf-8,<html><head><style>body { margin: 0; padding: 0; overflow: hidden; display: flex; justify-content: center; align-items: center; height: 100%; }</style></head><body>没有配置机器人地址</body></html>';
|
||||
chatWindow.style.visibility = 'unset';
|
||||
return;
|
||||
}
|
||||
let fastUID = result.fastUID;
|
||||
if (!fastUID || fastUID === '') {
|
||||
fastUID = generateUUID();
|
||||
chrome.storage.local.set({
|
||||
fastUID: fastUID
|
||||
});
|
||||
}
|
||||
chrome.runtime.sendMessage({
|
||||
action: "startRequestInterception",
|
||||
chatbotSrc: botSrc
|
||||
});
|
||||
console.log('fastUID:', fastUID);
|
||||
botSrc = botSrc + "&authToken=" + fastUID;
|
||||
if (botSrc.includes(result.shareId)) {
|
||||
botSrc = botSrc + "&chatId=" + result.chatId;
|
||||
}
|
||||
if (result.chatBotWidth && result.chatBotHeight) {
|
||||
chatWindow.style.width = result.chatBotWidth + 'px';
|
||||
chatWindow.style.height = result.chatBotHeight + 'px';
|
||||
} else {
|
||||
chatWindow.style.width = '400px';
|
||||
chatWindow.style.height = '700px';
|
||||
}
|
||||
iframe.src = 'about:blank';
|
||||
iframe.onload = function () {
|
||||
chatWindow.style.visibility = 'unset';
|
||||
}
|
||||
adjustIframePosition(chatWindow);
|
||||
enableResize(iframeWrapper);
|
||||
setTimeout(() => {
|
||||
iframe.src = botSrc;
|
||||
iframe.onload = function () {
|
||||
if (parseInt(chatWindow.style.width, 10) >= 900) {
|
||||
fullscreenBtn.style.top = '13px';
|
||||
fullscreenBtn.style.right = '60px';
|
||||
switchBtn.style.top = '13px';
|
||||
switchBtn.style.right = '90px';
|
||||
} else {
|
||||
fullscreenBtn.style.top = '6px';
|
||||
fullscreenBtn.style.right = '50px';
|
||||
switchBtn.style.top = '6px';
|
||||
switchBtn.style.right = '80px';
|
||||
}
|
||||
chatWindow.appendChild(fullscreenBtn);
|
||||
chatWindow.appendChild(switchBtn);
|
||||
const tmpEl = document.getElementById('configList');
|
||||
if (tmpEl) {
|
||||
chatWindow.removeChild(tmpEl);
|
||||
}
|
||||
};
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
ChatBtn.addEventListener('mousedown', (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (!chatBtnMouseX && !chatBtnMouseY) {
|
||||
chatBtnMouseX = e.clientX;
|
||||
chatBtnMouseY = e.clientY;
|
||||
}
|
||||
|
||||
chatBtnDown = true;
|
||||
});
|
||||
|
||||
window.addEventListener('mousemove', throttle(handleMouseMove, 16)); // 60fps
|
||||
window.addEventListener('mouseup', handleMouseUp);
|
||||
|
||||
function handleMouseMove(e) {
|
||||
e.stopPropagation();
|
||||
if (!canDrag || !chatBtnDown) return;
|
||||
|
||||
chatBtnDragged = true;
|
||||
const transformX = e.clientX - chatBtnMouseX;
|
||||
const transformY = e.clientY - chatBtnMouseY;
|
||||
|
||||
ChatBtn.style.transform = `translate3d(${transformX}px, ${transformY}px, 0)`;
|
||||
|
||||
adjustIframePosition(document.getElementById(chatWindowWrapperId));
|
||||
}
|
||||
|
||||
function handleMouseUp(e) {
|
||||
chatBtnDown = false;
|
||||
adjustIframePosition(document.getElementById(chatWindowWrapperId));
|
||||
|
||||
window.removeEventListener('mousemove', handleMouseMove);
|
||||
}
|
||||
|
||||
ChatBtn.appendChild(ChatBtnDiv);
|
||||
document.body.appendChild(ChatBtn);
|
||||
|
||||
function generateUUID() {
|
||||
const randomString = 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function () {
|
||||
const randomHex = (Math.random() * 16) | 0;
|
||||
return randomHex.toString(16);
|
||||
});
|
||||
|
||||
const timestamp = Date.now().toString(16);
|
||||
|
||||
const extraRandom = (Math.random() * 1e16).toString(16);
|
||||
|
||||
return `${randomString}-${timestamp}-${extraRandom}`;
|
||||
}
|
||||
|
||||
function adjustIframePosition(chatWindow) {
|
||||
const chatBtnRect = ChatBtn.getBoundingClientRect();
|
||||
const chatBtnWidth = chatBtnRect.width;
|
||||
const chatBtnHeight = chatBtnRect.height;
|
||||
const chatBtnLeft = chatBtnRect.left;
|
||||
const chatBtnTop = chatBtnRect.top;
|
||||
|
||||
const screenWidth = window.innerWidth;
|
||||
const screenHeight = window.innerHeight;
|
||||
|
||||
const iframeWidth = parseInt(chatWindow.style.width, 10);
|
||||
const iframeHeight = parseInt(chatWindow.style.height, 10);
|
||||
|
||||
const iframeTopLeft = {x: chatBtnLeft - iframeWidth, y: chatBtnTop - iframeHeight};
|
||||
const iframeTopRight = {x: chatBtnLeft + chatBtnWidth, y: chatBtnTop - iframeHeight};
|
||||
const iframeBottomLeft = {x: chatBtnLeft - iframeWidth, y: chatBtnTop + chatBtnHeight};
|
||||
const iframeBottomRight = {x: chatBtnLeft + chatBtnWidth, y: chatBtnTop + chatBtnHeight};
|
||||
|
||||
let bestPosition = iframeTopLeft;
|
||||
let bestDistance = Infinity;
|
||||
|
||||
const positions = [iframeTopLeft, iframeTopRight, iframeBottomLeft, iframeBottomRight];
|
||||
positions.forEach(position => {
|
||||
const distance = Math.sqrt(Math.pow(position.x, 2) + Math.pow(position.y, 2));
|
||||
|
||||
if (position.x + iframeWidth > screenWidth) {
|
||||
position.x = screenWidth - iframeWidth;
|
||||
}
|
||||
if (position.x < 0) {
|
||||
position.x = 0;
|
||||
}
|
||||
if (position.y + iframeHeight > screenHeight) {
|
||||
position.y = screenHeight - iframeHeight;
|
||||
}
|
||||
if (position.y < 0) {
|
||||
position.y = 0;
|
||||
}
|
||||
|
||||
if (distance < bestDistance) {
|
||||
bestPosition = position;
|
||||
bestDistance = distance;
|
||||
}
|
||||
});
|
||||
|
||||
chatWindow.style.left = `${bestPosition.x}px`;
|
||||
chatWindow.style.top = `${bestPosition.y}px`;
|
||||
}
|
||||
|
||||
function throttle(func, limit) {
|
||||
let lastFunc;
|
||||
let lastRan;
|
||||
return function () {
|
||||
const context = this;
|
||||
const args = arguments;
|
||||
if (!lastRan) {
|
||||
func.apply(context, args);
|
||||
lastRan = Date.now();
|
||||
} else {
|
||||
clearTimeout(lastFunc);
|
||||
lastFunc = setTimeout(function () {
|
||||
if ((Date.now() - lastRan) >= limit) {
|
||||
func.apply(context, args);
|
||||
lastRan = Date.now();
|
||||
}
|
||||
}, limit - (Date.now() - lastRan));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function enableResize(iframeWrapper) {
|
||||
let isResizing = false;
|
||||
let lastDownX = 0;
|
||||
let lastDownY = 0;
|
||||
let resizeDirection = '';
|
||||
|
||||
// 创建八个调整大小的句柄
|
||||
const handles = ['nw-resize', 'ne-resize', 'sw-resize', 'se-resize', 'n-resize', 's-resize', 'w-resize', 'e-resize'];
|
||||
const directions = ['tl', 'tr', 'bl', 'br', 't', 'b', 'l', 'r'];
|
||||
|
||||
handles.forEach((cursorType, index) => {
|
||||
const handle = createResizeHandle(cursorType);
|
||||
iframeWrapper.appendChild(handle);
|
||||
positionHandle(handle, directions[index]);
|
||||
handle.addEventListener('mousedown', (e) => startResizing(e, directions[index]));
|
||||
});
|
||||
|
||||
function createResizeHandle(cursorType) {
|
||||
const handle = document.createElement('div');
|
||||
handle.style.width = '15px';
|
||||
handle.style.height = '15px';
|
||||
handle.style.background = 'transparent';
|
||||
handle.style.position = 'absolute';
|
||||
handle.style.cursor = cursorType;
|
||||
return handle;
|
||||
}
|
||||
|
||||
function positionHandle(handle, direction) {
|
||||
switch (direction) {
|
||||
case 'tl':
|
||||
handle.style.top = '0';
|
||||
handle.style.left = '0';
|
||||
break;
|
||||
case 'tr':
|
||||
handle.style.top = '0';
|
||||
handle.style.right = '0';
|
||||
break;
|
||||
case 'bl':
|
||||
handle.style.bottom = '0';
|
||||
handle.style.left = '0';
|
||||
break;
|
||||
case 'br':
|
||||
handle.style.bottom = '0';
|
||||
handle.style.right = '0';
|
||||
break;
|
||||
case 't':
|
||||
handle.style.top = '0';
|
||||
handle.style.left = '50%';
|
||||
handle.style.transform = 'translateX(-50%)';
|
||||
handle.style.width = `${iframeWrapper.offsetWidth - 30}px`;
|
||||
handle.style.height = '3px';
|
||||
break;
|
||||
case 'b':
|
||||
handle.style.bottom = '0';
|
||||
handle.style.left = '50%';
|
||||
handle.style.transform = 'translateX(-50%)';
|
||||
handle.style.width = `${iframeWrapper.offsetWidth - 30}px`;
|
||||
handle.style.height = '3px';
|
||||
break;
|
||||
case 'l':
|
||||
handle.style.top = '50%';
|
||||
handle.style.left = '0';
|
||||
handle.style.transform = 'translateY(-50%)';
|
||||
handle.style.width = '3px';
|
||||
handle.style.height = `${iframeWrapper.offsetHeight - 30}px`;
|
||||
break;
|
||||
case 'r':
|
||||
handle.style.top = '50%';
|
||||
handle.style.right = '0';
|
||||
handle.style.transform = 'translateY(-50%)';
|
||||
handle.style.width = '3px';
|
||||
handle.style.height = `${iframeWrapper.offsetHeight - 30}px`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function startResizing(e, direction) {
|
||||
isResizing = true;
|
||||
lastDownX = e.clientX;
|
||||
lastDownY = e.clientY;
|
||||
resizeDirection = direction;
|
||||
iframeWrapper.style.pointerEvents = 'none'; // 禁用 iframe 的鼠标事件
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', throttle(handleResizeMouseMove, 50));
|
||||
document.addEventListener('mouseup', handleResizeMouseUp);
|
||||
|
||||
function handleResizeMouseMove(e) {
|
||||
if (!isResizing) return;
|
||||
|
||||
const offsetX = e.clientX - lastDownX;
|
||||
const offsetY = e.clientY - lastDownY;
|
||||
requestAnimationFrame(() => {
|
||||
switch (resizeDirection) {
|
||||
case 'tl':
|
||||
iframeWrapper.style.width = `${iframeWrapper.offsetWidth - offsetX}px`;
|
||||
iframeWrapper.style.height = `${iframeWrapper.offsetHeight - offsetY}px`;
|
||||
iframeWrapper.style.left = `${iframeWrapper.offsetLeft + offsetX}px`;
|
||||
iframeWrapper.style.top = `${iframeWrapper.offsetTop + offsetY}px`;
|
||||
break;
|
||||
case 'tr':
|
||||
iframeWrapper.style.width = `${iframeWrapper.offsetWidth + offsetX}px`;
|
||||
iframeWrapper.style.height = `${iframeWrapper.offsetHeight - offsetY}px`;
|
||||
iframeWrapper.style.top = `${iframeWrapper.offsetTop + offsetY}px`;
|
||||
break;
|
||||
case 'bl':
|
||||
iframeWrapper.style.width = `${iframeWrapper.offsetWidth - offsetX}px`;
|
||||
iframeWrapper.style.height = `${iframeWrapper.offsetHeight + offsetY}px`;
|
||||
iframeWrapper.style.left = `${iframeWrapper.offsetLeft + offsetX}px`;
|
||||
break;
|
||||
case 'br':
|
||||
iframeWrapper.style.width = `${iframeWrapper.offsetWidth + offsetX}px`;
|
||||
iframeWrapper.style.height = `${iframeWrapper.offsetHeight + offsetY}px`;
|
||||
break;
|
||||
case 't':
|
||||
iframeWrapper.style.height = `${iframeWrapper.offsetHeight - offsetY}px`;
|
||||
iframeWrapper.style.top = `${iframeWrapper.offsetTop + offsetY}px`;
|
||||
break;
|
||||
case 'b':
|
||||
iframeWrapper.style.height = `${iframeWrapper.offsetHeight + offsetY}px`;
|
||||
break;
|
||||
case 'l':
|
||||
iframeWrapper.style.width = `${iframeWrapper.offsetWidth - offsetX}px`;
|
||||
iframeWrapper.style.left = `${iframeWrapper.offsetLeft + offsetX}px`;
|
||||
break;
|
||||
case 'r':
|
||||
iframeWrapper.style.width = `${iframeWrapper.offsetWidth + offsetX}px`;
|
||||
break;
|
||||
}
|
||||
lastDownX = e.clientX;
|
||||
lastDownY = e.clientY;
|
||||
if (parseInt(iframeWrapper.style.width, 10) >= 900) {
|
||||
fullscreenBtn.style.top = '13px';
|
||||
fullscreenBtn.style.right = '60px';
|
||||
switchBtn.style.top = '13px';
|
||||
switchBtn.style.right = '90px';
|
||||
} else {
|
||||
fullscreenBtn.style.top = '6px';
|
||||
fullscreenBtn.style.right = '50px';
|
||||
switchBtn.style.top = '6px';
|
||||
switchBtn.style.right = '80px';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleResizeMouseUp() {
|
||||
console.log('handleResizeMouseUp');
|
||||
if (isResizing) {
|
||||
isResizing = false; // 将 isResizing 重置为 false
|
||||
enableResize(iframeWrapper);
|
||||
iframeWrapper.style.pointerEvents = 'auto'; // 恢复 iframe 的鼠标事件
|
||||
chrome.storage.local.set({
|
||||
chatBotWidth: iframeWrapper.offsetWidth,
|
||||
chatBotHeight: iframeWrapper.offsetHeight
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
@@ -0,0 +1,108 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Chatbot Extension</title>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
body,
|
||||
html {
|
||||
height: 600px;
|
||||
width: 800px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
color: #007BFF;
|
||||
}
|
||||
#chatbot-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#chatbot-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
border: none;
|
||||
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.config-btn-icon {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 8px;
|
||||
right: 50px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.fullScreen-icon {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 8px;
|
||||
right: 80px; /* Adjusted to position left of the config button */
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.overlay {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: opacity 0.3s ease;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.overlay-content {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
transition: transform 0.3s ease;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.overlay-content.show {
|
||||
transform: scale(1);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="chatbot-container">
|
||||
<div id="configOverlay" class="overlay" style="display: none;">
|
||||
<div class="overlay-content">
|
||||
未配置机器人,请点击右上角【设置】
|
||||
</div>
|
||||
</div>
|
||||
<iframe id="chatbot-iframe" allowfullscreen allow="microphone"></iframe>
|
||||
<!-- <webview id="chatbot-iframe" allowfullscreen></webview>-->
|
||||
<img src="../img/fullScreen.png" class="fullScreen-icon" id="fullScreen">
|
||||
<img src="../img/setting.png" class="config-btn-icon" id="config-btn">
|
||||
</div>
|
||||
<script src="popup.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@@ -0,0 +1,66 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const chatbotIframe = document.getElementById('chatbot-iframe');
|
||||
const fullScreenBtn = document.getElementById('fullScreen');
|
||||
const configBtn = document.getElementById('config-btn');
|
||||
const overlay = document.getElementById('configOverlay');
|
||||
configBtn.addEventListener('click', function () {
|
||||
window.location.href = 'setting.html'
|
||||
});
|
||||
|
||||
// 监听 chatbotIframe 加载完成事件
|
||||
chatbotIframe.addEventListener('load', function() {
|
||||
// 当 iframe 加载完成后显示按钮
|
||||
fullScreenBtn.style.display = 'inline-block';
|
||||
configBtn.style.display = 'inline-block';
|
||||
});
|
||||
chrome.storage.local.get(["chatbotSrc", "shareId", "chatId", "fastUID"]).then((result) => {
|
||||
const botSrc = result.chatbotSrc;
|
||||
let fastUID = result.fastUID;
|
||||
if (!fastUID || fastUID === '') {
|
||||
fastUID = generateUUID();
|
||||
chrome.storage.local.set({
|
||||
fastUID: fastUID
|
||||
});
|
||||
}
|
||||
console.log('fastUID is', fastUID);
|
||||
console.log("chatbotSrc is " + botSrc);
|
||||
console.log("shareId is " + result.shareId);
|
||||
console.log("chatId is " + result.chatId);
|
||||
chatbotIframe.src = result.chatbotSrc + "&authToken=" + fastUID;
|
||||
if (!botSrc || botSrc === 'about:blank' || botSrc === '') {
|
||||
overlay.style.display = 'flex';
|
||||
} else {
|
||||
if (botSrc.includes(result.shareId)) {
|
||||
chatbotIframe.src = chatbotIframe.src + "&chatId=" + result.chatId;
|
||||
console.log('chatbotIframe.src', chatbotIframe.src);
|
||||
}
|
||||
overlay.style.display = 'none';
|
||||
chrome.runtime.sendMessage({
|
||||
action: "startRequestInterception",
|
||||
chatbotSrc: botSrc
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
fullScreenBtn.addEventListener('click', function () {
|
||||
const iframe = document.getElementById('chatbot-iframe');
|
||||
if (iframe) {
|
||||
const iframeSrc = iframe.src;
|
||||
console.log('fullScreenSrc', iframeSrc)
|
||||
chrome.tabs.create({url: iframeSrc});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function generateUUID() {
|
||||
const randomString = 'xxxxxxxxxxxxxxxx'.replace(/[x]/g, function () {
|
||||
const randomHex = (Math.random() * 16) | 0;
|
||||
return randomHex.toString(16);
|
||||
});
|
||||
|
||||
const timestamp = Date.now().toString(16);
|
||||
|
||||
const extraRandom = (Math.random() * 1e16).toString(16);
|
||||
|
||||
return `${randomString}-${timestamp}-${extraRandom}`;
|
||||
}
|
@@ -0,0 +1,382 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>配置项管理器</title>
|
||||
<style>
|
||||
body, html {
|
||||
height: 585px;
|
||||
width: 800px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
#startChatButton {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
width: 95px;
|
||||
height: 30px;
|
||||
background-color: #1890ff;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
clip-path: polygon(10% 0%, 100% 0%, 100% 100%, 10% 100%, 0% 50%);
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
table, form {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
text-align: center;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#configTable th:nth-child(1),
|
||||
#configTable td:nth-child(1) {
|
||||
width: 150px; /* 设置第1列的宽度 */
|
||||
}
|
||||
|
||||
#configTable th:nth-child(3),
|
||||
#configTable td:nth-child(3) {
|
||||
width: 70px; /* 设置第3列的宽度 */
|
||||
}
|
||||
|
||||
#configTable th:nth-child(4),
|
||||
#configTable td:nth-child(4) {
|
||||
width: 50px; /* 设置第4列的宽度 */
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 800px;
|
||||
border-collapse: collapse;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 10px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
position: relative;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
form {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
input[type="text"], input[type="number"] {
|
||||
width: calc(100% - 10px);
|
||||
padding: 8px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
transform: translateY(15%);
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #1890ff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
#addConfigButton {
|
||||
left: 10px;
|
||||
width: 60px;
|
||||
height: 30px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.editName, .editUrl {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.editButton[disabled] {
|
||||
color: #666; /* Gray text color */
|
||||
cursor: not-allowed; /* Change cursor to not-allowed */
|
||||
}
|
||||
|
||||
.editButton, .deleteButton {
|
||||
background-color: transparent; /* Remove background color */
|
||||
border: none;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: #1890ff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.button-group button {
|
||||
margin-right: 5px; /* Add space between buttons */
|
||||
}
|
||||
|
||||
.editButton:hover {
|
||||
background-color: transparent;
|
||||
color: #4CAF50; /* Green color on hover */
|
||||
}
|
||||
|
||||
.deleteButton:hover {
|
||||
background-color: transparent;
|
||||
color: #f44336; /* Red color on hover */
|
||||
}
|
||||
|
||||
.editButton + div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
left: -20px; /* 调整位置以适应左侧显示 */
|
||||
top: 0; /* 确保与编辑按钮对齐 */
|
||||
}
|
||||
|
||||
.editButton + div span {
|
||||
cursor: pointer;
|
||||
margin: 5px 0; /* 上下间距 */
|
||||
}
|
||||
|
||||
.icon-hover {
|
||||
transition: transform 0.3s ease; /* 添加过渡效果 */
|
||||
}
|
||||
|
||||
.icon-hover:hover {
|
||||
transform: scale(2); /* 鼠标悬停时放大1.2倍 */
|
||||
}
|
||||
|
||||
.custom-radio {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.custom-radio input[type="radio"] {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.custom-radio .radio-mark {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
background-color: #f1f1f1;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #d9d9d9;
|
||||
z-index: 1;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.custom-radio:hover input ~ .radio-mark {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.custom-radio input:checked ~ .radio-mark {
|
||||
background-color: #1890ff;
|
||||
border-color: #1890ff;
|
||||
}
|
||||
|
||||
.custom-radio .radio-mark:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: white;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.custom-radio input:checked ~ .radio-mark:after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.custom-radio .radio-mark:active {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
.custom-radio .radio-mark:active:after {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.custom-radio .radio-mark:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.custom-radio .radio-mark:hover:after {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
#errorMsg {
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
padding: 10px 15px;
|
||||
border-radius: 5px;
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
/* 为确认和取消按钮添加伪元素 */
|
||||
.confirmButton::before,
|
||||
.cancelButton::before {
|
||||
content: ""; /* 初始时,伪元素的内容为空 */
|
||||
}
|
||||
|
||||
/* 当鼠标悬停在按钮上时,显示文字 */
|
||||
.confirmButton:hover::before {
|
||||
content: "确认";
|
||||
}
|
||||
|
||||
.cancelButton:hover::before {
|
||||
content: "取消";
|
||||
}
|
||||
|
||||
.confirmButton::before,
|
||||
.cancelButton::before {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 8px;
|
||||
color: darkgray;
|
||||
white-space: nowrap;
|
||||
transition: content 0.3s;
|
||||
}
|
||||
|
||||
.confirmButton::before {
|
||||
top: 10%;
|
||||
}
|
||||
|
||||
.cancelButton::before {
|
||||
top: 80%;
|
||||
}
|
||||
|
||||
.config-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.config-item label {
|
||||
margin-right: 10px;
|
||||
width: 120px;
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.config-item input[type="number"] {
|
||||
width: 80px;
|
||||
padding: 6px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<script src="setting.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<button id="startChatButton">开始聊天</button>
|
||||
<div id="errorMsg"></div>
|
||||
<h1>ChatBot配置</h1>
|
||||
<h3>页面机器人:</h3>
|
||||
<div style="display: flex">
|
||||
<div class="config-item">
|
||||
<label for="showChatBotSwitch">显示:</label>
|
||||
<input type="checkbox" id="showChatBotSwitch">
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<label for="chatBotWidthInput">宽度(px):</label>
|
||||
<input type="number" id="chatBotWidthInput" min="1">
|
||||
</div>
|
||||
|
||||
<div class="config-item">
|
||||
<label for="chatBotHeightInput">高度(px):</label>
|
||||
<input type="number" id="chatBotHeightInput" min="1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>机器人地址:</h3>
|
||||
<table id="configTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>名称</th>
|
||||
<th>地址</th>
|
||||
<th>操作</th>
|
||||
<th>选择BOT</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="configList"> <!-- Table rows will be dynamically added using JavaScript --> </tbody>
|
||||
</table>
|
||||
<button id="addConfigButton">添 加</button>
|
||||
</body>
|
||||
</html>
|
@@ -0,0 +1,283 @@
|
||||
let chatbotSrc = '';
|
||||
let configs = [];
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async function () {
|
||||
const storageData = await chrome.storage.local.get(["chatbotSrc", "configs", "showChatBot", "chatBotWidth", "chatBotHeight"]);
|
||||
chatbotSrc = storageData.chatbotSrc || '';
|
||||
configs = storageData.configs || [];
|
||||
const showChatBot = storageData.showChatBot === undefined ? true : storageData.showChatBot;
|
||||
const chatBotWidth = storageData.chatBotWidth || 400;
|
||||
const chatBotHeight = storageData.chatBotHeight || 700;
|
||||
|
||||
await loadConfigs(configs, chatbotSrc);
|
||||
|
||||
document.getElementById('addConfigButton').addEventListener('click', handleAddButtonClick);
|
||||
document.getElementById('startChatButton').addEventListener('click', () => window.location.href = 'popup.html');
|
||||
|
||||
// 监听开关和输入框变化事件
|
||||
const showChatBotSwitch = document.getElementById('showChatBotSwitch');
|
||||
const chatBotWidthInput = document.getElementById('chatBotWidthInput');
|
||||
const chatBotHeightInput = document.getElementById('chatBotHeightInput');
|
||||
|
||||
showChatBotSwitch.addEventListener('change', () => handleShowChatBotChange(showChatBotSwitch.checked));
|
||||
chatBotWidthInput.addEventListener('change', () => handleChatBotWidthChange(chatBotWidthInput.value));
|
||||
chatBotHeightInput.addEventListener('change', () => handleChatBotHeightChange(chatBotHeightInput.value));
|
||||
|
||||
// 初始化开关和输入框的值
|
||||
showChatBotSwitch.checked = showChatBot;
|
||||
chatBotWidthInput.value = chatBotWidth;
|
||||
chatBotHeightInput.value = chatBotHeight;
|
||||
|
||||
});
|
||||
|
||||
async function loadConfigs(configs, chatbotSrc) {
|
||||
const configList = document.getElementById('configList');
|
||||
configList.innerHTML = '';
|
||||
configs.forEach(config => {
|
||||
const row = createConfigRow(config, chatbotSrc);
|
||||
configList.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
function createConfigRow(config, chatbotSrc) {
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${config.name}</td>
|
||||
<td>${config.url}</td>
|
||||
<td>
|
||||
<button type="button" class="editButton">编辑</button>
|
||||
<span>|</span>
|
||||
<button type="button" class="deleteButton">删除</button>
|
||||
</td>
|
||||
<td>
|
||||
<label class="custom-radio">
|
||||
<input type="radio" name="selectBot" class="selectBot" ${config.url === chatbotSrc ? 'checked' : ''}>
|
||||
<span class="radio-mark"></span>
|
||||
</label>
|
||||
</td>
|
||||
`;
|
||||
row.querySelector('.editButton').addEventListener('click', () => handleEditButtonClick(row, config));
|
||||
row.querySelector('.deleteButton').addEventListener('click', () => handleDeleteButtonClick(row, config));
|
||||
row.querySelector('.selectBot').addEventListener('change', () => handleSelectBotChange(config.url));
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
async function handleDeleteButtonClick(row, config) {
|
||||
const configList = document.getElementById('configList');
|
||||
const index = Array.from(configList.children).indexOf(row);
|
||||
const selectedUrl = config.url;
|
||||
if (selectedUrl === chatbotSrc) {
|
||||
chatbotSrc = 'about:blank';
|
||||
await updateStorage('chatbotSrc', chatbotSrc);
|
||||
await updateStorage('chatId', '');
|
||||
await updateStorage('shareId', '');
|
||||
}
|
||||
configs.splice(index, 1);
|
||||
await updateStorage('configs', configs);
|
||||
row.remove();
|
||||
}
|
||||
|
||||
async function handleSelectBotChange(url) {
|
||||
chatbotSrc = url;
|
||||
await updateStorage('chatbotSrc', chatbotSrc);
|
||||
updateSelectedRadioButton();
|
||||
}
|
||||
|
||||
function updateSelectedRadioButton() {
|
||||
document.querySelectorAll('.selectBot').forEach(radio => {
|
||||
if (radio.closest('tr').querySelector('td:nth-child(2)').textContent === chatbotSrc) {
|
||||
radio.checked = true;
|
||||
} else {
|
||||
radio.checked = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function showError(message) {
|
||||
const errorMsg = document.getElementById('errorMsg');
|
||||
errorMsg.textContent = message;
|
||||
errorMsg.style.opacity = 1; // 显示错误消息
|
||||
|
||||
// 设置一个定时器,在5秒后隐藏错误消息
|
||||
setTimeout(() => {
|
||||
errorMsg.style.opacity = 0; // 隐藏错误消息
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
|
||||
async function updateStorage(key, value) {
|
||||
try {
|
||||
await chrome.storage.local.set({[key]: value});
|
||||
console.log(`${key} 已更新: ${value}`);
|
||||
} catch (error) {
|
||||
console.error(`更新 ${key} 出错:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
function showEditControls(row, isNewConfig = false, config = null) {
|
||||
const nameCell = row.querySelector('td:nth-child(1)');
|
||||
const urlCell = row.querySelector('td:nth-child(2)');
|
||||
const name = isNewConfig ? '' : config.name;
|
||||
const url = isNewConfig ? '' : config.url;
|
||||
|
||||
nameCell.innerHTML = `<input type="text" class="editName" value="${name}">`;
|
||||
urlCell.innerHTML = `<input type="text" class="editUrl" value="${url}">`;
|
||||
|
||||
const iconContainer = document.createElement('div');
|
||||
iconContainer.style.display = 'flex';
|
||||
iconContainer.style.flexDirection = 'column';
|
||||
iconContainer.style.position = 'absolute';
|
||||
iconContainer.style.top = '15px';
|
||||
iconContainer.style.left = '-5px';
|
||||
|
||||
const confirmIcon = document.createElement('span');
|
||||
confirmIcon.textContent = '√';
|
||||
confirmIcon.style.color = 'green';
|
||||
confirmIcon.style.cursor = 'pointer';
|
||||
confirmIcon.style.margin = '0 0 10px 0';
|
||||
confirmIcon.classList.add('icon-hover');
|
||||
confirmIcon.classList.add('confirmButton');
|
||||
confirmIcon.addEventListener('click', () => {
|
||||
handleConfirmButtonClick(row, isNewConfig);
|
||||
});
|
||||
|
||||
const cancelIcon = document.createElement('span');
|
||||
cancelIcon.textContent = 'X';
|
||||
cancelIcon.style.color = 'red';
|
||||
cancelIcon.style.cursor = 'pointer';
|
||||
cancelIcon.classList.add('icon-hover');
|
||||
cancelIcon.classList.add('cancelButton')
|
||||
cancelIcon.addEventListener('click', () => {
|
||||
handleCancelButtonClick(row, isNewConfig);
|
||||
});
|
||||
|
||||
iconContainer.appendChild(confirmIcon);
|
||||
iconContainer.appendChild(cancelIcon);
|
||||
|
||||
const cell = row.querySelector('td:nth-child(3)');
|
||||
cell.insertBefore(iconContainer, cell.firstChild);
|
||||
}
|
||||
|
||||
function handleAddButtonClick() {
|
||||
const newRow = document.createElement('tr');
|
||||
newRow.innerHTML = `
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
`;
|
||||
document.getElementById('configList').appendChild(newRow);
|
||||
showEditControls(newRow, true);
|
||||
}
|
||||
|
||||
function handleEditButtonClick(row, config) {
|
||||
disableAllEditButtons();
|
||||
showEditControls(row, false, config);
|
||||
}
|
||||
|
||||
function isConfigUnique(name, url, index) {
|
||||
return !configs.some((config, i) =>
|
||||
i !== index && (config.name === name || config.url === url)
|
||||
);
|
||||
}
|
||||
|
||||
function checkConfig(name, url, index) {
|
||||
let errorMsg = '';
|
||||
if (!name || !url) {
|
||||
errorMsg = '名称和地址都是必填项。';
|
||||
} else if (!isConfigUnique(name, url, index)) {
|
||||
errorMsg = '名称或地址不能重复。';
|
||||
}
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
function handleConfirmButtonClick(row, isNewConfig = false) {
|
||||
const name = row.querySelector('.editName').value;
|
||||
const url = row.querySelector('.editUrl').value;
|
||||
const index = isNewConfig ? -1 : Array.from(document.getElementById('configList').children).indexOf(row);
|
||||
const errorMsg = checkConfig(name, url, index);
|
||||
if (errorMsg) {
|
||||
showError(errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNewConfig) {
|
||||
const newConfig = {name, url};
|
||||
configs.push(newConfig);
|
||||
updateStorage('configs', configs);
|
||||
|
||||
} else {
|
||||
const config = configs[index];
|
||||
config.name = name;
|
||||
if (config.url === chatbotSrc) {
|
||||
chatbotSrc = url;
|
||||
updateStorage('chatId', '');
|
||||
updateStorage('shareId', '');
|
||||
chrome.runtime.sendMessage({
|
||||
action: "startRequestInterception",
|
||||
chatbotSrc: chatbotSrc
|
||||
});
|
||||
}
|
||||
config.url = url;
|
||||
updateStorage('configs', configs);
|
||||
updateStorage('chatbotSrc', chatbotSrc);
|
||||
}
|
||||
loadConfigs(configs, chatbotSrc);
|
||||
row.remove();
|
||||
enableAllEditButtons();
|
||||
}
|
||||
|
||||
|
||||
function handleCancelButtonClick(row, isNewConfig = false) {
|
||||
if (isNewConfig) {
|
||||
row.remove();
|
||||
} else {
|
||||
const index = Array.from(document.getElementById('configList').children).indexOf(row);
|
||||
const config = configs[index];
|
||||
row.querySelector('td:nth-child(1)').textContent = config.name;
|
||||
row.querySelector('td:nth-child(2)').textContent = config.url;
|
||||
row.querySelector('.editButton').disabled = false;
|
||||
// 移除编辑模式下的确认和取消按钮
|
||||
const iconContainer = row.querySelector('td:nth-child(3) > div');
|
||||
if (iconContainer) {
|
||||
iconContainer.remove();
|
||||
}
|
||||
}
|
||||
enableAllEditButtons();
|
||||
}
|
||||
|
||||
async function handleShowChatBotChange(showChatBot) {
|
||||
await updateStorage('showChatBot', showChatBot);
|
||||
}
|
||||
|
||||
async function handleChatBotWidthChange(width) {
|
||||
const parsedWidth = parseInt(width);
|
||||
if (!isNaN(parsedWidth)) {
|
||||
await updateStorage('chatBotWidth', parsedWidth);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleChatBotHeightChange(height) {
|
||||
const parsedHeight = parseInt(height);
|
||||
if (!isNaN(parsedHeight)) {
|
||||
await updateStorage('chatBotHeight', parsedHeight);
|
||||
}
|
||||
}
|
||||
|
||||
function disableAllEditButtons() {
|
||||
const allEditButtons = document.querySelectorAll('.editButton');
|
||||
allEditButtons.forEach(button => {
|
||||
button.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
function enableAllEditButtons() {
|
||||
const allEditButtons = document.querySelectorAll('.editButton');
|
||||
allEditButtons.forEach(button => {
|
||||
button.disabled = false;
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user