痛点:每到周五写周报,总要翻遍整个工时系统,手动复制粘贴、整理汇总,耗时又枯燥。
解法:一个浏览器插件,自动抓取工时数据,一键生成 AI 总结。本文将完整分享实现思路与核心代码。
一、效果预览
安装脚本后,打开工时管理系统,你会看到:
- 自动捕获:页面加载后自动拦截接口数据,无需手动操作
- 浮动面板:右下角出现两个渐变按钮
- 一键复制:点击即可复制整理好的周报内容
- AI 总结:调用本地 Ollama 大模型,智能提炼关键成果

二、核心原理:如何"拦截"接口数据
现代网页应用通常通过 XMLHttpRequest 或 Fetch API 与服务器通信。我们的核心思路是:"劫持"这些原生方法,在数据返回时插一脚。
2.1 拦截 XMLHttpRequest
javascript
// 保存原始方法
const originalXhrOpen = XMLHttpRequest.prototype.open;
const originalXhrSend = XMLHttpRequest.prototype.send;
// 重写 open 方法,记录请求的 URL
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
this._url = url; // 保存 URL 供后续判断
this._method = method;
return originalXhrOpen.apply(this, [method, url, ...rest]);
};
// 重写 send 方法,监听特定接口的响应
XMLHttpRequest.prototype.send = function(...args) {
// 判断是否是目标工时接口
if (this._url && this._url.includes('/pms/project/job/time/getJobTimeCalendar')) {
this.addEventListener('load', function() {
const response = this.responseText;
const data = JSON.parse(response);
if (data.code === 200) {
// 存储到 localStorage,方便后续使用
localStorage.setItem('capturedJobTimeData', JSON.stringify(data.data));
console.log('[工时助手] 数据已捕获');
}
});
}
return originalXhrSend.apply(this, args);
};
2.2 拦截 Fetch API
现代应用越来越多使用 fetch,同样需要处理:
javascript
const originalFetch = window.fetch;
window.fetch = function(input, init) {
const url = typeof input === 'string' ? input : input.url;
return originalFetch.apply(this, arguments).then(response => {
if (url && url.includes(targetUrl)) {
// 注意:fetch 返回的 Response 只能读取一次,需要克隆
const clonedResponse = response.clone();
clonedResponse.json().then(data => {
if (data.code === 200) {
capturedData = data.data;
console.log('[工时助手] Fetch 捕获到数据');
}
});
}
return response; // 必须返回原始响应
});
};
知识点 :
response.clone()是必需的,因为 Response body 是流式读取的,消费后就不能再次读取。克隆一份专门用于脚本处理,不影响页面原有逻辑。
三、数据处理:从原始 JSON 到周报文本
捕获到的是原始日历数据,需要:
- 筛选本周(周一至周五)的数据
- 按项目名称分组汇总
- 格式化为易读的周报格式
3.1 计算本周日期范围
javascript
function getCurrentWeekDates() {
const today = new Date();
const dayOfWeek = today.getDay(); // 0=周日, 1=周一...
// 计算周一的偏移量(周日时回退6天到上周一)
const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek;
const dates = [];
for (let i = 0; i < 5; i++) { // 周一到周五
const date = new Date(today);
date.setDate(today.getDate() + mondayOffset + i);
dates.push(formatDate(date)); // 格式化为 YYYY-MM-DD
}
return dates;
}
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
3.2 数据分组与格式化
javascript
function processData(data) {
const weekDates = getCurrentWeekDates();
const projectMap = new Map();
// 遍历本周每一天
weekDates.forEach(dateStr => {
// 在返回的数组中找到对应日期的数据
const dayData = data.find(item => item.date === dateStr);
if (dayData && dayData.list) {
dayData.list.forEach(item => {
const projectName = item.projectShortName || '其他';
const content = item.remark || '';
if (content) {
// 按项目分组存储
if (projectMap.has(projectName)) {
projectMap.get(projectName).push(content);
} else {
projectMap.set(projectName, [content]);
}
}
});
}
});
// 生成周报文本:一、项目A:xxx;二、项目B:xxx
let result = '';
let index = 1;
projectMap.forEach((contents, projectName) => {
const mergedContent = contents.join('\n');
result += `${numberToChinese(index)}、${projectName}:${mergedContent}\n`;
index++;
});
return result.trim();
}
---
## 四、AI 集成:调用本地 Ollama 大模型
为了不让周报看起来只是机械堆砌,脚本集成了 **Ollama** 本地大模型,自动提炼关键成果。
### 4.1 Ollama 配置
```javascript
const OLLAMA_URL = 'http://localhost:11434/api/generate';
const MODEL_NAME = 'qwen2.5:3b'; // 可自行替换为其他模型
Ollama 是一个在本地运行大语言模型的工具,无需联网,保护数据隐私。安装后执行
ollama run qwen2.5:3b即可使用。
4.2 调用 AI 进行总结
javascript
async function summarizeWithAI(content) {
// 精心设计的提示词,指导 AI 的输出格式
const prompt = `请将以下本周工作内容进行智能总结,要求:
1. 按项目维度汇总工作内容
2. 合并相似的工作项
3. 提炼关键工作成果
4. 使用简洁、专业的语言
5. 输出格式保持清晰易读
原始工作内容:
${content}
请输出总结后的工作内容:`;
return new Promise((resolve, reject) => {
// GM_xmlhttpRequest 是油猴脚本特有的跨域请求 API
GM_xmlhttpRequest({
method: 'POST',
url: OLLAMA_URL,
headers: {
'Content-Type': 'application/json'
},
data: JSON.stringify({
model: MODEL_NAME,
prompt: prompt,
stream: false, // 非流式,等待完整响应
options: {
temperature: 0.3, // 低温度 = 更确定性的输出
max_tokens: 800
}
}),
onload: function(response) {
const result = JSON.parse(response.responseText);
if (result.response) {
resolve(result.response);
}
},
onerror: function(error) {
reject('请求失败,请确认 Ollama 服务是否运行');
},
timeout: 60000 // 本地模型可能较慢,给足时间
});
});
}
五、UI 交互:纯原生 DOM 构建浮动面板
脚本没有依赖任何 UI 库,完全使用原生 DOM API 创建界面,保证轻量和兼容性。
5.1 创建渐变按钮
javascript
function createButtonPanel() {
const panel = document.createElement('div');
panel.id = 'tm-button-panel';
panel.style.cssText = `
position: fixed;
bottom: 10px;
right: 10px;
z-index: 999999;
display: flex;
flex-direction: column;
gap: 8px;
`;
// 查看原始数据按钮(青绿渐变)
const viewBtn = document.createElement('button');
viewBtn.innerText = '📋 查看本周工时';
viewBtn.style.cssText = getButtonStyle('#11998e', '#38ef7d');
viewBtn.addEventListener('click', () => {
const text = localStorage.getItem('formattedWorkContent');
if (text) showDataModal(text, '原始格式');
});
// AI 总结按钮(粉紫渐变)
const aiBtn = document.createElement('button');
aiBtn.innerText = '🤖 AI 智能总结';
aiBtn.style.cssText = getButtonStyle('#f093fb', '#f5576c');
aiBtn.addEventListener('click', async () => {
showLoadingModal(); // 显示加载动画
try {
const summary = await summarizeWithAI(formattedText);
closeLoadingModal();
showDataModal(summary, 'AI 智能总结');
} catch (err) {
showNotification('AI 总结失败: ' + err, true);
}
});
panel.appendChild(viewBtn);
panel.appendChild(aiBtn);
document.body.appendChild(panel);
}
function getButtonStyle(color1, color2) {
return `
padding: 10px 16px;
background: linear-gradient(135deg, ${color1} 0%, ${color2} 100%);
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 13px;
font-weight: bold;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
`;
}
六、完整脚本使用指南
6.1 安装步骤
-
安装浏览器扩展 :Chrome/Edge 商店搜索 Tampermonkey(篡改猴)
-
新建脚本:点击扩展图标 → "添加新脚本"
-
粘贴代码:将完整脚本粘贴到编辑器中,保存(Ctrl+S)
6.2 配置 Ollama(可选)
如需 AI 总结功能:
bash
# 1. 安装 Ollama(https://ollama.com)
# 2. 拉取模型
ollama pull qwen2.5:3b
# 3. 启动服务(保持终端运行)
ollama run qwen2.5:3b
6.3 使用流程
| 步骤 | 操作 | 效果 |
|---|---|---|
| 1 | 登录工时系统 | 脚本自动在后台捕获数据 |
| 2 | 点击"📋 查看本周工时" | 弹出原始数据弹窗 |
| 3 | 点击"📝 复制到剪贴板" | 内容已复制,可直接粘贴到周报 |
| 4 | (可选)点击"🤖 AI 智能总结" | 等待 AI 处理后生成精炼版本 |
七、技术亮点总结
| 技术点 | 实现方式 | 价值 |
|---|---|---|
| 接口拦截 | 重写 XHR/Fetch 原型方法 | 无侵入式获取数据,无需后端配合 |
| 数据持久化 | localStorage 缓存 | 页面刷新不丢失,支持延迟查看 |
| AI 集成 | Ollama 本地大模型 | 数据不出本机,保护隐私 |
| 跨域请求 | GM_xmlhttpRequest | 油猴脚本特权 API,突破浏览器 CORS 限制 |
| 零依赖 UI | 原生 DOM + CSS | 体积小、加载快、无冲突 |
结语
技术服务的终极目标是解决真实问题。一个 200 行的油猴脚本,可能看起来不够"高大上",但它每周为你节省半小时,让你从重复劳动中解放出来------这就是技术赋能的价值。
如果你也有类似的数据整理痛点,不妨动手试试,或许一个脚本就能改变你的工作流。
相关资源:
- Tampermonkey 官方文档:www.tampermonkey.net/documentati...
- Ollama 模型库:ollama.com/library
