From acaed399e13d725e0ae5382a2424cc7b296b3d6b Mon Sep 17 00:00:00 2001 From: tmn Date: Fri, 28 Nov 2025 13:56:51 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BC=81=E4=B8=9A=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E8=8E=B7=E5=8F=96=E7=BE=A4=E8=81=8A=E9=BB=91=E5=90=8D?= =?UTF-8?q?=E5=8D=95=E6=8F=92=E4=BB=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 + manifest.json | 15 +++ popup.html | 19 +++ popup.js | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 352 insertions(+) create mode 100644 .gitignore create mode 100644 manifest.json create mode 100644 popup.html create mode 100644 popup.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a65d639 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea + +/dist/ + +.vscode \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..a50c2cd --- /dev/null +++ b/manifest.json @@ -0,0 +1,15 @@ +{ + "manifest_version": 3, + "name": "企业微信数据获取", + "version": "3.1.1", + "permissions": [ + "activeTab", + "scripting" + ], + "host_permissions": [ + "https://work.weixin.qq.com/*" + ], + "action": { + "default_popup": "popup.html" + } +} diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..98439b0 --- /dev/null +++ b/popup.html @@ -0,0 +1,19 @@ + + + + + + + +

企业微信数据获取器

+ + +
点击上方按钮获取数据...
+ + + \ No newline at end of file diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..8123b28 --- /dev/null +++ b/popup.js @@ -0,0 +1,313 @@ +// 当popup页面的DOM内容完全加载后执行 +document.addEventListener('DOMContentLoaded', function () { + // 获取页面中的按钮元素 + const getStudentsBtn = document.getElementById('get-students-btn'); + const getBlacklistBtn = document.getElementById('get-blacklist-btn'); + const dataDisplay = document.getElementById('data-display'); + + // 全局变量存储企业信息 + let enterpriseInfo = { + corpId: null, + corpName: null + }; + + /** + * 获取企业信息 + * @param {number} tabId - 标签页ID + * @returns {Object} 企业信息 {corpId, corpName} + */ + async function getEnterpriseInfo(tabId) { + try { + const enterpriseResult = await chrome.scripting.executeScript({ + target: {tabId: tabId}, + func: () => { + return fetch('https://work.weixin.qq.com/wework_admin/profile/quotaupdate/log?lang=zh_CN&f=json', { + method: 'GET', + credentials: 'include' + }).then(r => r.json()); + } + }); + + // 提取企业信息 + const enterpriseData = enterpriseResult[0].result; + if (enterpriseData && enterpriseData.data && enterpriseData.data.basecertinfo) { + const info = { + corpId: enterpriseData.data.basecertinfo.appid, + corpName: enterpriseData.data.basecertinfo.subject_name + }; + + console.log('企业信息获取成功:', info); + return info; + } else { + throw new Error('无法获取企业信息:响应数据格式异常'); + } + } catch (error) { + console.error('获取企业信息失败:', error); + throw new Error(`获取企业信息失败: ${error.message}`); + } + } + + // 获取学员列表按钮的点击事件监听器 + getStudentsBtn.addEventListener('click', async () => { + // 获取当前激活的标签页 + const [tab] = await chrome.tabs.query({active: true, currentWindow: true}); + + try { + // 第一步:获取企业信息 + dataDisplay.textContent = '正在获取企业信息...'; + enterpriseInfo = await getEnterpriseInfo(tab.id); + + // 第二步:获取所有学员数据 + dataDisplay.textContent = '正在获取学员数据...'; + const allStudentsData = await getAllStudentsData(tab.id); + + // 第三步:发送数据到指定接口 + dataDisplay.textContent = '正在发送数据...'; + await sendStudentsData(allStudentsData, enterpriseInfo); + + // 完成 + dataDisplay.textContent = `✅ 学员数据处理完成!\n\n企业信息:\nAppID: ${enterpriseInfo.corpId}\n企业名称: ${enterpriseInfo.corpName}\n\n学员数量: ${allStudentsData.length}\n\n数据已成功发送到服务器。`; + + } catch (error) { + console.error('处理失败:', error); + dataDisplay.textContent = `❌ 处理失败: ${error.message}`; + } + }); + + // 获取黑名单按钮的点击事件监听器 + getBlacklistBtn.addEventListener('click', async () => { + // 获取当前激活的标签页 + const [tab] = await chrome.tabs.query({active: true, currentWindow: true}); + + try { + // 第一步:获取企业信息 + dataDisplay.textContent = '正在获取企业信息...'; + enterpriseInfo = await getEnterpriseInfo(tab.id); + + // 第二步:获取所有黑名单数据 + dataDisplay.textContent = '正在获取黑名单数据...'; + const allBlacklistData = await getAllBlacklistData(tab.id); + + // 第三步:发送数据到指定接口 + dataDisplay.textContent = '正在发送数据...'; + await sendBlacklistData(allBlacklistData, enterpriseInfo); + + // 完成 + dataDisplay.textContent = `✅ 黑名单数据处理完成!\n\n企业信息:\nAppID: ${enterpriseInfo.corpId}\n企业名称: ${enterpriseInfo.corpName}\n\n黑名单数量: ${allBlacklistData.length}\n\n数据已成功发送到服务器。`; + + } catch (error) { + console.error('处理失败:', error); + dataDisplay.textContent = `❌ 处理失败: ${error.message}`; + } + }); + + /** + * 获取所有学员数据(处理分页) + * @param {number} tabId - 标签页ID + * @returns {Array} 所有学员数据 + */ + async function getAllStudentsData(tabId) { + let allStudents = []; + let lastPageMaxId = ''; + let hasMore = true; + let pageCount = 0; + + while (hasMore) { + pageCount++; + dataDisplay.textContent = `正在获取学员数据... 第${pageCount}页,已获取${allStudents.length}条`; + + // 构建URL编码的请求参数(application/x-www-form-urlencoded) + const params = new URLSearchParams(); + + params.append('page', pageCount.toString()); + params.append('time_since', '1744560000'); + params.append('time_before', '1744991999'); + params.append('last_page_max_id', lastPageMaxId); + params.append('perpage', '10000'); // 每页100条,可根据实际情况调整 + + const result = await chrome.scripting.executeScript({ + target: {tabId: tabId}, + func: (formDataStr) => { + return fetch('https://work.weixin.qq.com/wework_admin/customer/list?lang=zh_CN&f=json', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', // 关键:设置正确的Content-Type + }, + body: formDataStr, + credentials: 'include' + }).then(r => r.json()); + }, + args: [params.toString()] + }); + + const data = result[0].result; + + if (data && data.data) { + // 更新数据解析逻辑:从 data.data.detail_list.items 获取学员数据 + if (data.data.detail_list && data.data.detail_list.items && data.data.detail_list.items.length > 0) { + allStudents = allStudents.concat(data.data.detail_list.items); + } + + // 更新分页参数:使用 has_more 判断是否还有更多数据 + hasMore = data.data.has_more || false; + lastPageMaxId = data.data.max_id || ''; + + console.log(`第${pageCount}页学员获取完成,本页${data.data.detail_list?.items?.length || 0}条,总计${allStudents.length}条,has_more: ${hasMore}`); + + // 避免请求过快,添加小延迟 + await new Promise(resolve => setTimeout(resolve, 100)); + + } else { + throw new Error('获取学员数据失败:响应数据格式异常'); + } + } + + console.log('学员数据获取完成,总计:', allStudents.length, '条'); + return allStudents; + } + + /** + * 获取所有黑名单数据(处理分页) + * @param {number} tabId - 标签页ID + * @returns {Array} 所有黑名单数据 + */ + async function getAllBlacklistData(tabId) { + let allBlockedCustomers = []; + let lastPageMaxId = ''; + let isEnd = false; + let pageCount = 0; + + while (!isEnd) { + pageCount++; + dataDisplay.textContent = `正在获取黑名单数据... 第${pageCount}页,已获取${allBlockedCustomers.length}条`; + + // 构建请求URL + const url = `https://work.weixin.qq.com/wework_admin/groupchat/blockedCustomers?lang=zh_CN&f=json&pageSize=15000&last_page_max_id=${lastPageMaxId}`; + + const result = await chrome.scripting.executeScript({ + target: {tabId: tabId}, + func: (requestUrl) => { + return fetch(requestUrl, { + method: 'GET', + credentials: 'include' + }).then(r => r.json()); + }, + args: [url] + }); + + const data = result[0].result; + + if (data && data.data) { + // 添加当前页的黑名单数据到总数组 + if (data.data.blockedCustomers && data.data.blockedCustomers.length > 0) { + allBlockedCustomers = allBlockedCustomers.concat(data.data.blockedCustomers); + } + + // 更新分页参数 + isEnd = data.data.is_end; + lastPageMaxId = data.data.last_page_max_id || ''; + + console.log(`第${pageCount}页黑名单获取完成,本页${data.data.blockedCustomers?.length || 0}条,总计${allBlockedCustomers.length}条,is_end: ${isEnd}`); + + // 避免请求过快,添加小延迟 + await new Promise(resolve => setTimeout(resolve, 200)); + + } else { + throw new Error('获取黑名单数据失败:响应数据格式异常'); + } + } + + console.log('黑名单数据获取完成,总计:', allBlockedCustomers.length, '条'); + return allBlockedCustomers; + } + + /** + * 发送学员数据到指定接口 + * @param {Array} studentsData - 学员数据 + * @param {Object} enterpriseInfo - 企业信息 + */ + async function sendStudentsData(studentsData, enterpriseInfo) { + // 构建要发送的数据 + const payload = { + enterpriseInfo: enterpriseInfo, + studentsData: studentsData, + totalCount: studentsData.length, + fetchTime: new Date().toISOString() + }; + + console.log('准备发送学员数据:', { + enterprise: enterpriseInfo, + count: studentsData.length, + sample: studentsData.slice(0, 2) // 只显示前2条作为示例 + }); + + // // TODO: 替换为您的实际接口地址 + // const apiEndpoint = 'http://192.168.0.133:7788/wework/students/import'; + // + // try { + // const response = await fetch(apiEndpoint, { + // method: 'POST', + // headers: { + // 'Content-Type': 'application/json', + // }, + // body: JSON.stringify(payload) + // }); + // + // if (!response.ok) { + // throw new Error(`服务器响应错误: ${response.status} ${response.statusText}`); + // } + // + // const result = await response.json(); + // console.log('学员数据发送成功:', result); + // + // } catch (error) { + // console.error('发送学员数据失败:', error); + // throw new Error(`发送学员数据失败: ${error.message}`); + // } + } + + /** + * 发送黑名单数据到指定接口 + * @param {Array} blacklistData - 黑名单数据 + * @param {Object} enterpriseInfo - 企业信息 + */ + async function sendBlacklistData(blacklistData, enterpriseInfo) { + // 构建要发送的数据 + const payload = { + enterpriseInfo: enterpriseInfo, + blacklistData: blacklistData, + totalCount: blacklistData.length, + fetchTime: new Date().toISOString() + }; + + console.log('准备发送黑名单数据:', { + enterprise: enterpriseInfo, + count: blacklistData.length, + sample: blacklistData.slice(0, 2) // 只显示前2条作为示例 + }); + + // TODO: 替换为您的实际接口地址 + const apiEndpoint = 'http://192.168.0.133:7788/wework/blacklist/import'; + + try { + const response = await fetch(apiEndpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload) + }); + + if (!response.ok) { + throw new Error(`服务器响应错误: ${response.status} ${response.statusText}`); + } + + const result = await response.json(); + console.log('黑名单数据发送成功:', result); + + } catch (error) { + console.error('发送黑名单数据失败:', error); + throw new Error(`发送黑名单数据失败: ${error.message}`); + } + } +});