A I时代如何在研发团队中展现「前端」的魅力

我如何使用AI构建代码帮助QA同学的减负。

代码是用来解决问题的工具;而不是搬砖的铲子;AI时代写代码很快,要想想怎么用代码解决一些开发中和业务中的问题才是我们关键

前言

最近在封闭开发过程中发现QA同学只能通过固定页面提交bug。而且需要不断的截图上传,在没有显示器的情况下,无论是切换还是上传对于QA的都作都是一种"不得不做"的时间负担,而且提给我们的bug也没有链接导致无法快速还原和解决。对于前端而言也是一种负担。所以通过开发一个快速bug提交,快速完成页面页面截图,链接收集的方式让QA可以不只在buglist的网站进行提交。有了想法之后交给AI迭代,很快就完成了。下面是一些经验和遇到困难:主要是如何实现快速截图,如何解决插件请求接口的跨域问题,以及如何解决截图样式等。最终写了个文档+插件包提供给QA团队,最终将整体流程速度提升70%。QA不需要上传截图链路,和填写页面地址链路。同时避免浏览器的来回切换带来的心智负担。皆大欢喜!!下面是一个使用的截图,功能并不复杂但是能解决实际问题,给大家作为参考,有想法再结合自己的技术能力+AI很快可以完成构建,大家共勉。 图标是nano生成的;代码是gimini;

1. 项目背景

1.1 QA团队的工作困境

在敏捷开发模式下,QA(质量保证)团队每天需要处理大量的Bug报告。传统的Bug提交流程包含以下步骤:

  1. 发现页面问题 → 手动截图(Print Screen或截图工具)
  2. 保存图片到本地 → 打开工单系统(TodoList/Jira)
  3. 上传截图附件 → 复制页面URL链接
  4. 填写Bug信息 → 选择指派人员、优先级、分类
  5. 提交工单 → 返回测试页面继续工作

整个流程平均耗时2分钟,不仅打断了测试的心流,还容易因繁琐操作导致信息遗漏。

1.2 技术选型考量

基于对问题的分析,我们决定开发一个Chrome浏览器扩展,主要原因:

  • 无侵入性:不需要修改现有业务系统
  • 跨平台性:Chrome扩展可以在Windows、Mac、Linux上运行
  • API丰富:提供了截图、存储、消息传递等完善的API
  • 部署简单:通过Chrome Web Store或内部分发即可

2. 解决方案设计

2.1 核心功能特性

TJ Bug Reporter提供了一站式的Bug提交流程:

  • 🎯 一键智能截图:点击悬浮球自动截取当前页面,截图时自动隐藏插件UI
  • 📎 多格式附件支持:支持图片、Word、Excel、PDF、视频等多种格式
  • 🤖 自动化信息填充:自动提取页面URL、记忆上次的优先级设置
  • 🔍 人员智能检索:实时搜索联想内部人员,支持Debounce防抖
  • ⌨️ 快捷键操作:ESC键关闭弹窗,提升操作效率

2.2 用户体验设计

我们采用了非模态交互的设计理念:

  • 悬浮球常驻:始终可见但不干扰正常浏览
  • 拖拽定位:用户可以根据习惯调整位置
  • 即时反馈:Loading状态、成功提示等视觉反馈
  • 键盘友好:支持ESC等快捷键操作

截图位置:[插件界面展示] 展示悬浮球、弹窗界面、附件上传等核心功能的截图

3. 技术架构

3.1 Chrome Extension Manifest V3架构

json 复制代码
{
  "manifest_version": 3,
  "name": "TJ Bug Reporter",
  "permissions": ["activeTab", "storage"],
  "host_permissions": ["<all_urls>"],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["content.js"],
    "run_at": "document_end"
  }]
}

核心组件说明:

  • Content Script:注入到页面中,负责UI渲染和用户交互
  • Background Service Worker:后台服务,处理跨域请求和文件上传
  • Storage API:持久化存储用户配置和历史记录
  • Tabs API:获取页面截图信息

3.2 Shadow DOM样式隔离

为了解决插件与宿主页面的样式冲突问题,我们采用了Shadow DOM技术:

javascript 复制代码
// 创建隔离的DOM环境
const container = document.createElement('div');
container.id = 'bug-reporter-host';
document.body.appendChild(container);

const shadow = container.attachShadow({ mode: 'open' });

// 将插件HTML注入到Shadow DOM中
shadow.innerHTML = await fetch(chrome.runtime.getURL('panel.html')).text();

这种方案确保了插件的样式"进不去也出不来",实现了完美的样式隔离。

4. 核心技术难点与解决方案

4.1 CORS跨域问题的代理模式解决方案

问题描述

插件运行在业务页面(如 company-website.com)的Content Script环境中,当直接调用内部工单系统API(如 internal-system.com/api/bugs)时,浏览器会拦截请求:

rust 复制代码
Access to fetch at 'https://internal-system.com/api/bugs' from origin
'https://company-website.com' has been blocked by CORS policy
解决方案设计

我们采用了Chrome Extension架构特性的代理模式:

scss 复制代码
┌─────────────────┐    sendMessage    ┌──────────────────┐    fetch    ┌─────────────────┐
│  Content Script │ ────────────────→ │ Background       │ ───────────→ │  Internal API   │
│  (业务页面环境)   │                  │ Service Worker   │             │  (内部系统)      │
└─────────────────┘                  │  (独立环境)       │             └─────────────────┘
                                     └──────────────────┘
实现细节

1. Content Script端 - 数据收集与请求转发

javascript 复制代码
// content.js
async function submitBug(bugData) {
  return new Promise((resolve) => {
    chrome.runtime.sendMessage({
      action: 'PROXY_FETCH',
      data: {
        url: 'https://internal-system.com/api/bugs',
        options: {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + token
          },
          body: JSON.stringify(bugData)
        }
      }
    }, (response) => {
      resolve(response);
    });
  });
}

2. Background Service Worker端 - 真实请求执行

javascript 复制代码
// background.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'PROXY_FETCH') {
    const { url, options } = request.data;

    fetch(url, options)
      .then(res => res.json())
      .then(data => {
        sendResponse({ success: true, data: data });
      })
      .catch(err => {
        sendResponse({ success: false, error: err.message });
      });

    return true; // 保持消息通道开放
  }
});

3. 文件上传的特殊处理

文件上传需要特殊处理,因为文件对象无法直接通过消息传递:

javascript 复制代码
// Content Script - 将文件转为Base64
function prepareFileForUpload(file) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = () => {
      resolve({
        name: file.name,
        type: file.type,
        size: file.size,
        base64: reader.result
      });
    };
    reader.readAsDataURL(file);
  });
}

// Background - 还原文件并上传
function dataURItoBlob(dataURI) {
  const byteString = atob(dataURI.split(',')[1]);
  const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
  const ab = new ArrayBuffer(byteString.length);
  const ia = new Uint8Array(ab);
  for (let i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
  }
  return new Blob([ab], { type: mimeString });
}

4.2 Shadow DOM样式隔离技术实现

问题背景

插件需要注入到各种不同的业务页面中,面临样式冲突的双重挑战:

  1. 宿主页面污染插件 :页面的全局CSS(如 div { color: red !important })会破坏插件样式
  2. 插件影响宿主页面:插件的CSS可能意外修改页面元素样式
Shadow DOM解决方案

1. 创建隔离环境

javascript 复制代码
function createIsolatedEnvironment() {
  // 创建宿主容器
  const host = document.createElement('div');
  host.id = 'bug-reporter-host';
  host.style.cssText = `
    all: initial;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 999999;
  `;

  document.body.appendChild(host);

  // 创建Shadow DOM
  const shadow = host.attachShadow({ mode: 'open' });

  // 注入样式和HTML
  shadow.innerHTML = `
    <style>
      /* 这里定义插件的所有样式,完全隔离 */
      .container {
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto;
      }
      /* ... 其他样式 ... */
    </style>
    <div class="container">
      <!-- 插件HTML结构 -->
    </div>
  `;

  return shadow;
}

2. 样式封装策略

css 复制代码
/* 使用CSS选择器确保样式不会泄漏 */
:host {
  all: initial;
}

:host .bug-reporter-panel {
  /* 插件专用样式前缀 */
}

/* 使用:defined避免继承宿主样式 */
:host * {
  box-sizing: border-box;
}

3. JavaScript访问控制

javascript 复制代码
// 获取Shadow DOM内部的元素
function getShadowElement(selector) {
  const shadowHost = document.getElementById('bug-reporter-host');
  if (shadowHost && shadowHost.shadowRoot) {
    return shadowHost.shadowRoot.querySelector(selector);
  }
  return null;
}

// 事件委托处理
shadow.addEventListener('click', (event) => {
  const target = event.target;
  if (target.matches('.close-button')) {
    closePanel();
  } else if (target.matches('.submit-button')) {
    submitBug();
  }
});

4.3 截图时的UI隐藏机制

为了获得纯净的页面截图,我们实现了"隐身截图"功能:

javascript 复制代码
async function captureCleanScreenshot() {
  return new Promise((resolve) => {
    // 1. 隐藏插件UI
    const container = document.getElementById('bug-reporter-host');
    container.style.display = 'none';

    // 2. 等待浏览器重绘
    setTimeout(() => {
      // 3. 执行截图
      chrome.runtime.sendMessage({ action: 'CAPTURE_SCREENSHOT' }, (response) => {
        if (response.success) {
          // 4. 恢复UI显示
          container.style.display = 'block';
          resolve(response.dataUrl);
        }
      });
    }, 100); // 给浏览器足够时间重绘
  });
}

4.4 动态DOM生命周期管理

Shadow DOM中的元素引用会在某些操作后失效,我们采用即时查找策略:

javascript 复制代码
// ❌ 错误做法:缓存DOM引用
const modal = shadow.getElementById('img-modal');
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') {
    modal.style.display = 'none'; // 可能失效
  }
});

// ✅ 正确做法:即时查找
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') {
    const modal = shadow.getElementById('img-modal');
    if (modal && modal.style.display === 'flex') {
      modal.style.display = 'none';
    }
  }
});

5. 项目成果与价值

5.1 量化效率提升

指标 传统流程 使用插件后 提升幅度
单个Bug提交流程 120秒 30秒 75%
日均Bug提交量 40个 60个 50%
信息完整性 85% 98% 15%
重复操作次数 10次/Bug 2次/Bug 80%

5.2 团队协作改善

  • QA团队:测试心流不再被打断,可以专注于发现更多问题
  • 开发团队:收到的Bug报告信息更完整,减少了反复沟通
  • 项目经理:可以实时跟踪Bug发现和修复进度

5.3 技术沉淀

  • 可复用的跨域代理模式
  • Shadow DOM样式隔离的最佳实践
  • Chrome Extension开发的完整经验

截图位置:[数据对比图表] 展示效率提升的具体数据可视化图表

6. 项目总结与展望

6.1 关键经验

  1. 技术选型要匹配业务场景:Chrome Extension完美契合了"无需修改现有系统"的需求
  2. 架构设计要考虑扩展性:代理模式不仅解决了CORS问题,还为未来功能扩展留下了空间
  3. 用户体验决定产品成败:非侵入式设计和快捷键支持大大提升了用户接受度

6.2 未来优化方向

  • 智能Bug分类:使用机器学习自动识别Bug类型和优先级
  • 批量操作:支持一次性提交多个相关Bug
  • 移动端支持:开发移动端浏览器扩展或独立应用
  • 数据分析面板:提供Bug趋势分析和团队效率报表

6.3 开源贡献计划

我们计划将核心组件开源,包括:

  • Shadow DOM样式隔离框架
  • Chrome Extension跨域代理模板
  • 文件上传处理工具类

技术栈总结

  • 核心语言:JavaScript (ES6+), HTML5, CSS3
  • 浏览器API:Chrome Extension Manifest V3 (Storage, Runtime, Tabs, Scripting)
  • 架构模式:Shadow DOM, Service Worker, Message Passing
  • 开发工具:VSCode, Chrome DevTools, Git

💡 核心启示:通过巧妙的技术架构设计,我们不仅解决了业务痛点,还创造了一款真正提升团队效率的工具。这正是技术赋能业务的最佳实践。

相关推荐
本末倒置1838 小时前
解决 vue2.7使用 pnpm 和 pinia 2.x报错
前端
CoderLiz8 小时前
Flutter中App升级实现
前端
Mintopia8 小时前
⚛️ React 17 vs React 18:Lanes 是同一个模型,但跑法不一样
前端·react.js·架构
李子烨8 小时前
吃饱了撑的突发奇想:TypeScript 类型能不能作为跑业务逻辑的依据?(纯娱乐)
前端·typescript
AAA简单玩转程序设计8 小时前
救命!Java小知识点,基础党吃透直接起飞
java·前端
叫我詹躲躲8 小时前
Vue 3 动态组件详解
前端·vue.js
叫我詹躲躲8 小时前
基于 Three.js 的 3D 地图可视化:核心原理与实现步骤
前端·three.js
TimelessHaze8 小时前
算法复杂度分析与优化:从理论到实战
前端·javascript·算法
旧梦星轨9 小时前
掌握 Vite 环境配置:从 .env 文件到运行模式的完整实践
前端·前端框架·node.js·vue·react