npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

issues-reporter-plugin

v0.1.7

Published

嵌入式问题上报插件

Readme

issues-reporter-plugin 项目描述

1. 项目概述

issues-reporter-plugin 是一个独立的外部前端插件,用于嵌入到各个业务子系统(如 BDC 不动产登记中心各模块)中,实现自动化提取报错信息,并将 Bug 信息固化为标准结构,为下游团队提供可直接复现、信息完整的标准文档。

插件以 TypeScript + 原生 DOM 构建,零前端框架依赖,一套代码可同时支持 Vue 2/3、React、Angular 以及原生 JS 项目接入。


2. 技术选型

| 维度 | 选型 | 说明 | |------|------|------| | 技术栈 | TypeScript + 原生 DOM | 零框架依赖,一套代码支持 Vue 2/3、React、Angular、原生 JS | | 构建工具 | Vite | 极速冷启动,HMR 更快,原生 ES Module 支持 | | 截图引擎 | SnapDOM(DOM 序列化)+ getDisplayMedia(精准捕获) | SnapDOM 基于 SVG foreignObject 由浏览器真实渲染,还原度高;精准模式像素级抓帧、零 DOM 遍历 | | 样式 | 原生 CSS | 无预处理器依赖,浏览器原生支持,避免与宿主样式冲突 | | UI 实现 | 原生 DOM API | createElement / appendChild / addEventListener,无框架绑定 | | Word 导出 | docx 库 | 纯 JS 生成,样式精确可控 | | PDF 导出 | jspdf + autotable | 原生支持中文,表格插件成熟 |

设计原则: UI 层采用纯原生 DOM + TypeScript 实现,不依赖 Vue、React、Angular 等任何前端框架。核心逻辑层(异常捕获、Bug 构建器、截图引擎、导出服务)本来就是纯 TS,零框架依赖,可在任何技术栈的项目中一致使用。


3. 架构设计

采用三层架构设计,各层职责清晰:

┌─────────────────────────────────────────────────────────┐
│  第 1 层:核心逻辑层(纯 TS,零框架依赖)                  │
│  ├── HTTP 拦截器(axios / fetch 双拦截)                  │
│  ├── 统一异常捕获协调器(HttpInterceptor)                 │
│  │   ├── JS 运行时错误监听                                │
│  │   ├── Vue 错误处理(Vue 2/3)                          │
│  │   ├── Promise 未捕获拒绝监听                            │
│  │   ├── XMLHttpRequest 拦截器                            │
│  │   ├── console.error 拦截器                             │
│  │   └── 资源加载错误监听(img/script/css)                │
│  ├── 错误分类器(按来源与严重程度分类)                    │
│  ├── 截图引擎(SnapDOM / 精准标签页捕获)                 │
│  ├── Bug 构建器(标准结构)                               │
│  └── 导出服务(JSON / MD / CSV / Word / PDF)            │
├─────────────────────────────────────────────────────────┤
│  第 2 层:UI 层(纯 DOM + TypeScript)                     │
│  ├── 悬浮工具栏(两个入口:创建 / 列表)                   │
│  ├── Bug 弹窗                                            │
│  │   ├── 模块一:我的问题清单(issueList)                 │
│  │   │   └── 展示当前用户已提交到后端的问题列表             │
│  │   └── 模块二:创建问题(createPreflight)               │
│  │       └── 选取本地捕获的 Bug → 填写标题/描述 → 提交后端  │
│  └── 截图标注画布(矩形 / 箭头 / 文字 / 马赛克)          │
├─────────────────────────────────────────────────────────┤
│  第 3 层:分发适配层                                      │
│  ├── npm 模式(插件完全控制截图)                         │
│  └── iframe 模式(宿主提供截图钩子,插件调用)             │
└─────────────────────────────────────────────────────────┘

所有异常捕获模块统一输出 CaptureErrorInfo,由 NpmAdapter.handleCaptureError() 统一处理:分类 → 去重 → 截图 → 构建 Bug 报告 → 存储到本地 → 回调通知。用户点击"创建"时,本地 Bug 作为候选数据带入创建表单,最终提交到后端。


4. 核心能力

4.1 自动异常捕获(后台静默运行)

插件启动后自动监听以下七类异常,捕获到的 Bug 暂存于本地内存,等待用户通过"创建问题"提交到后端:

| 来源 | 监听方式 | 捕获内容 | 默认是否开启 | |------|---------|---------|------------| | http-error | axios / fetch 拦截 | URL、method、status、请求参数、响应体 | 是 | | js-error | window.onerror | message、filename、lineno、colno、stack | 是 | | vue-error | Vue.config.errorHandler / app.config.errorHandler | 组件名、props、info、error.stack | 否(需显式设置 Vue 实例) | | promise-error | window.unhandledrejection | reason、reason.stack | 是 | | xhr-error | monkey-patch XMLHttpRequest | URL、method、headers、body、status、错误类型 | 是 | | console-error | monkey-patch console.error | 调用参数列表 | 否 | | resource-error | window.addEventListener('error', ..., true) | 资源标签名、src / href | 是 |

每类异常都生成统一的 CaptureErrorInfo,保留完整上下文(堆栈、组件、资源 URL、请求参数等),由 ErrorClassifier 按来源分级为 critical / high / medium / low

自动截图: 接口报错时自动截取当前页面(可配置 delay 等待错误提示框弹出)。截图引擎与性能调度见 4.7 截图方案

忽略规则: 支持配置忽略特定 URL、状态码、业务码,避免误报。

4.2 模块一:我的问题清单(issueList)

点击悬浮工具栏 "列表" 按钮,弹窗展示当前用户已提交到后端的全部问题。

  • 数据来源:GET /issues-api/issues(后端按当前登录用户过滤)
  • 展示字段:问题编号、标题、来源、状态、严重程度、指派给、上报人、创建时间
  • 操作:点击某行可跳转查看问题详情(含截图、接口信息、环境信息等)

4.3 模块二:创建问题(createPreflight)

点击悬浮工具栏 "创建" 按钮,弹窗展示本地已捕获的 Bug 列表,用户勾选后填写标题、严重程度、描述,可选截图标注,最终提交到后端生成问题单。

  • 数据来源:插件运行期间自动捕获并存入本地的 Bug 列表
  • 创建流程:选取 Bug → 填写标题 / 描述 / 严重程度 → 截图标注(可选) → 提交后端(POST /issues-api/issues
  • 支持截图标注(矩形框、箭头、文字、马赛克)
  • 支持撤销 / 重做操作

4.4 多格式导出

支持批量导出 Bug 为多种格式:

| 格式 | 用途 | |------|------| | JSON | 标准数据,适合系统对接 | | Markdown | 文档报告,适合 Git 归档 | | CSV | 表格数据,适合 Excel 分析 | | Word | 可编辑文档,适合协作打印 | | PDF | 只读文档,适合归档提交 |

4.5 AI 员工 Inbox 导出

支持将 Bug 一键推送到局域网内指定 AI 员工电脑的本地 Inbox 目录,由该电脑上的集成 AI 自动监听并处理。支持 JSON / Markdown / Word / PDF 四种导出格式后发送。

4.6 标准化输出结构

所有 Bug 信息统一固化为标准 JSON 结构(BugReport),包含:

  • 基础信息(ID、来源、严重程度、时间)
  • 环境信息(子系统、浏览器、路由、分辨率)
  • 接口信息(URL、方法、参数、响应)
  • 描述信息(标题、自动描述、手动描述)
  • 截图标注(Base64 图片 + 标注数据)
  • 扩展信息(标签、上报人、自定义字段、源详情 errorDetails

4.7 截图方案

截图采用双引擎 + 空闲调度 + Worker 编码 + IndexedDB 工作集的架构,目标是在复杂页面(二三维地图、大量 iframe)上把主线程阻塞压缩到最低,同时控制常驻内存占用。

4.7.1 双截图引擎

| 引擎 | 触发方式 | 原理 | 适用场景 | |------|---------|------|---------| | 普通截图(默认) | 自动/手动截图 | SnapDOM:SVG foreignObject 由浏览器真实渲染当前视口,clip: 'viewport' 剪枝视口外子树 | 绝大多数页面;同域 iframe 由 IframeCapturer 逐个截取后合成到主截图 | | 精准截图 | 用户授权后替代普通引擎 | getDisplayMedia({ preferCurrentTab: true }) 抓取当前标签页真实渲染帧 | 像素级还原 WebGL 地图与跨域 iframe;零 DOM 遍历、零序列化、主线程几乎零阻塞 |

精准模式说明:

  • HTTPS 安全上下文 + Chromium 系浏览器(Chrome 94+)可用,isSupported() 特性检测决定「精准」按钮是否显示(位于悬浮工具栏)
  • 必须在用户点击时发起授权(浏览器限制);授权一次后 MediaStream 常驻,后续抓帧不再弹授权窗
  • 用户点击浏览器「停止共享」→ track.ended → 自动停用,回退 SnapDOM 路径
  • WebGL 地图:普通 SnapDOM 无法读取 WebGL 画布内容(preserveDrawingBuffer: false 帧合成后缓冲清空),ImagePreprocessor 会在截图前劫持一次 requestAnimationFrame,在地图渲染的同帧将 canvas 拷贝为 2D 画布临时替换 DOM,截完恢复

4.7.2 自动截图性能调度(防卡顿)

自动截图(错误触发)经过多层调度,保证报错瞬间的用户交互不受影响:

错误触发
  → 错误风暴断路器(StormGuard):风暴期直接跳过,避免昂贵 DOM 操作雪上加霜
  → 15s 冷却窗口:窗口内只做一次 SnapDOM 序列化,手动截图不受限
  → 并发锁 + 排队:正在截图时新请求入队等待
  → 300ms 尾沿 debounce:密集报错时让开页面最忙时刻
  → requestIdleCallback 空闲帧执行(2s 超时兜底)
  → 实际截图

单次截图的主线程成本压缩手段:

| 手段 | 效果 | |------|------| | clip: 'viewport' | 视口外子树在样式计算/资源内联前被剪枝,长页面不全文档光栅化 | | scale: 0.75 × dpr: 1 | 留证用途降采样,HiDPI 屏(dpr=2)像素量不翻倍 | | embedFonts: false | 跳过非图标字体内联(字体抓取+解析是序列化重头) | | excludeMode: 'remove' | 插件自身 UI 直接从克隆树丢弃(fixed 定位不影响布局) | | 空闲预热 preCache | mount 后空闲时预内联字体/图片/CSS,首次真实截图不再承担全部资源内联成本 | | Worker 编码 | JPEG 编码/压缩/iframe 合成经 createImageBitmap 零拷贝转移至 Worker(OffscreenCanvas),主线程无 canvas.toBlob 长任务;Worker 不可用时自动回退主线程 |

复杂页面单次自动截图的主线程占用约 70–350ms,且被拆散在空闲帧执行;相比全文档遍历 + 主线程编码的传统方案下降约一个数量级。

4.7.3 内存管理:IndexedDB 工作集 + 惰性水合

截图 Blob 不长期驻留内存,常驻内存从「每张截图几百 KB」降为「一个占位字符串」:

  • 写入:Bug 入库时截图 Blob write-through 镜像到 IndexedDB,写成功后立即释放内存——revoke Object URL、url 换成 idb:{bugId}:{index} 占位符、删除 blob 字段
  • 读取(惰性水合):消费点(详情展示/导出 Word·PDF·JSON/提交后端/发送 AI)在使用前调 hydrateBugs() 从 IDB 读回内存,用完 releaseBugs() 释放
  • 提交链路:提交前统一水合,截图二进制以 ref: 占位符写入 JSON 元数据、multipart files 携带二进制,files 数量与截图数一致
  • 隐私模式兜底:IDB 不可用(隐私浏览/配额/禁用)时写入返回失败,内存 Blob 常驻不释放,所有消费点按 blob 优先正常工作
  • 会话启动时清空上次残留的 IDB 记录(不跨会话恢复),防止无上限增长

4.7.4 截图模式配置(screenshotMode)

运行时配置项 screenshotMode,可由管理平台「系统设置 → 插件配置 → 截图配置」统一下发(GET /issues-api/system-settings/plugin),也可在构造配置中静态指定;缺失或非法值回退 normal

| 值 | 行为 | |---|---| | off | 关闭截图:不自动截图、「精准」按钮隐藏;Bug 照常捕获上报(无图),用户手动上传/粘贴图片不受限 | | normal | 普通 DOM 序列化截图(默认),「精准」按钮不显示 | | precision | 悬浮工具栏显示「精准」按钮(HTTPS + Chromium),授权后自动截图走像素级抓帧,未授权时回退 SnapDOM |


5. 分发方式

插件支持三种集成方式:

  1. npm 包引入import IssuesReporter from 'issues-reporter-plugin',适用于可修改源码的子项目

    • 插件完全控制截图
    • 直接访问宿主 DOM
  2. iframe 嵌入 — 通过 <iframe src="..."> 方式嵌入,适用于无法修改源码的遗留系统

    • 宿主提供截图钩子(window.IssuesReporterScreenshot
    • 插件通过 postMessage 调用
    • 支持 HTTP/HTTPS 混合环境(协议自适应)
  3. <script> 自动初始化 — 直接引用构建产物 issues-reporter.auto.umd.js,通过 data-* 属性完成配置,无需编写业务代码

    • 自动发现 Vue 2 / Vue 3 实例并绑定 errorHandler
    • 自动发现页面上的 axios 实例
    • 脚本解析后立即启动所有错误监听器,DOM 就绪后挂载 UI

6. 项目集成示例

6.1 Vue 3 项目

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import IssuesReporter from 'issues-reporter-plugin'
import axios from 'axios'

const app = createApp(App)
app.mount('#app')

const issuesReporter = new IssuesReporter({
  projectKey: 'BDC',        // 必填:项目标识(对应后端 Project.key)
  projectName: '不动产登记中心', // 必填:项目名称,首次上报时自动创建
  version: 'v2.0.0',        // 必填:版本号,对应 Issue.version
  token: 'eyJhbGc...',      // 必填(与 externalUserInfo 二选一):JWT token 登录
  // externalUserInfo: { userName: 'admin', userNickname: '管理员' }, // 或传用户信息免密登录
  // server: '',             // 后端地址为空时使用当前页面域名;跨域时填写完整前缀
})

// 注入 axios 实例(可选,用于精确提取请求参数)
issuesReporter.setAxiosInstance(axios)

// 注入 Vue 实例,开启 Vue 组件错误监控
issuesReporter.setVueInstance(app)

// 挂载 UI(悬浮工具栏 + Bug 弹窗)
issuesReporter.mount()

window.addEventListener('beforeunload', () => issuesReporter.destroy())

另一种登录方式:若外部系统无法提供 JWT,可改为传入 externalUserInfo(与 token 二选一),插件会调用 loginByUser 接口免密登录:

const issuesReporter = new IssuesReporter({
  projectKey: 'BDC',
  projectName: '不动产登记中心',
  version: 'v2.0.0',
  externalUserInfo: { userName: 'admin', userNickname: '管理员' },
})

其余参数(screenshotOptionsignorejsErrorconsoleError 等)均有合理默认值,完整说明见 6.7 关键配置说明

6.2 Vue 2 项目

// main.js
import Vue from 'vue'
import App from './App.vue'
import IssuesReporter from 'issues-reporter-plugin'
import axios from 'axios'

new Vue({ render: h => h(App) }).$mount('#app')

const issuesReporter = new IssuesReporter({
  projectKey: 'PUB3',
  projectName: '智治平台',
  version: 'v2.0.0',
  token: 'eyJhbGc...', // 必填(与 externalUserInfo 二选一):JWT token 登录
  // externalUserInfo: { userName: 'admin', userNickname: '管理员' }, // 或传用户信息免密登录
})

issuesReporter.setAxiosInstance(Vue.prototype.$axios || axios)
issuesReporter.setVueInstance(Vue)
issuesReporter.mount()

window.addEventListener('beforeunload', () => issuesReporter.destroy())

6.3 React 项目

// App.tsx
import { useEffect } from 'react'
import IssuesReporter from 'issues-reporter-plugin'

function App() {
  useEffect(() => {
    const issuesReporter = new IssuesReporter({
      projectKey: 'REACT_APP',
      projectName: 'React 业务系统',
      version: 'v1.0.0',
      token: 'eyJhbGc...', // 必填(与 externalUserInfo 二选一)
      // externalUserInfo: { userName: 'admin', userNickname: '管理员' },
    })
    issuesReporter.mount()
    return () => issuesReporter.destroy()
  }, [])

  return <div>{/* 业务组件 */}</div>
}

export default App

6.4 Angular 项目

// app.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core'
import IssuesReporter from 'issues-reporter-plugin'

@Component({
  selector: 'app-root',
  template: '<router-outlet></router-outlet>'
})
export class AppComponent implements OnInit, OnDestroy {
  private issuesReporter!: IssuesReporter

  ngOnInit() {
    this.issuesReporter = new IssuesReporter({
      projectKey: 'NG_APP',
      projectName: 'Angular 业务系统',
      version: 'v1.0.0',
      token: 'eyJhbGc...', // 必填(与 externalUserInfo 二选一)
      // externalUserInfo: { userName: 'admin', userNickname: '管理员' },
    })
    this.issuesReporter.mount()
  }

  ngOnDestroy() {
    this.issuesReporter.destroy()
  }
}

6.5 自动初始化入口(<script> 零代码集成)

如果目标系统不想引入 npm 包或在业务代码里实例化插件,可以直接通过 <script> 引用自动初始化产物。推荐把脚本放在 <head> 或业务 bundle 之前,以便尽早启动错误监听,捕获 Vue 挂载阶段和早期接口错误。

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="//your-static-server/issues-reporter-plugin/0.2.20/style.css">
  <script
    src="//your-static-server/issues-reporter-plugin/0.2.20/issues-reporter.auto.umd.js"
    data-project-key="PUB3"
    data-token="eyJhbGc..."
    data-delay="600"
    data-vue-error="true"
    data-ignore-urls="/heartbeat/"
    data-ignore-business-codes="401"
  ></script>
</head>
<body>
  <div id="app"></div>
  <script src="/app.js"></script>
</body>
</html>

常用 data-* 属性:

| 属性 | 说明 | 示例 | |---|---|---| | data-project-key | 项目唯一标识,必填 | PUB3 | | data-project-name | 项目名称,首次上报时自动创建 | 智治平台 | | data-server | 后端接口前缀,为空时使用当前页面域名 | http://192.168.1.100:3000 | | data-token | JWT token(与 data-user-name 二选一),用于 loginByToken 免密登录 | eyJhbGc... | | data-user-name | 用户账号(与 data-token 二选一),用于 loginByUser 免密登录 | admin | | data-user-nickname | 用户昵称(配合 data-user-name 使用),首次创建用户时写入 | 管理员 | | data-delay | 截图延迟 ms | 600 | | data-quality | 截图质量 0-1 | 0.6 | | data-max-size | 截图最大字节 | 307200 | | data-show-flash | 截图闪光提示 | false | | data-auto-screenshot | 是否自动截图 | true | | data-js-error | 监听 JS 运行时错误 | true | | data-vue-error | 监听 Vue 错误 | true | | data-promise-error | 监听 Promise 未捕获拒绝 | true | | data-xhr-error | 监听 XHR 错误 | true | | data-console-error | 监听 console.error | false | | data-resource-error | 监听资源加载失败 | true | | data-ignore-urls | 忽略 URL/正则,逗号分隔 | /heartbeat/,/poll/ | | data-ignore-status-codes | 忽略 HTTP 状态码 | 401,500 | | data-ignore-business-codes | 忽略业务错误码 | 401,9999 | | data-ignore-methods | 忽略 HTTP 方法 | GET,OPTIONS |

布尔属性写 true 或只写属性名都算开启;要关闭直接省略该属性。

如需更高优先级覆盖,仍可保留 window.IssuesReporterConfig

<script>
  window.IssuesReporterConfig = { projectKey: 'PUB3', vueError: true }
</script>

配置合并优先级:window.IssuesReporterConfig > <script data-*>

注意: 自动初始化产物在脚本解析完成后立即启动错误监听器,UI 则在 DOM 就绪后挂载。若把脚本放在页面末尾,仍可能错过 <head> 或 body 前半段发生的错误,因此建议放在业务 JS 之前。

6.6 原生 JS 项目

<!-- index.html -->
<script type="module">
  import IssuesReporter from 'https://your-cdn.com/issues-reporter-plugin/dist/issues-reporter.es.js'

  const issuesReporter = new IssuesReporter({
    projectKey: 'NATIVE_APP',
    token: 'eyJhbGc...',            // 必填(与 externalUserInfo 二选一)
    enabled: true,
    autoScreenshot: true,
    screenshotOptions: { delay: 500 },
    jsError: true,
    promiseError: true,
    xhrError: true,
    resourceError: true
  })

  issuesReporter.mount()

  window.addEventListener('beforeunload', () => {
    issuesReporter.destroy()
  })
</script>

6.7 关键配置说明

| 配置项 | 说明 | 常用值 | |--------|------|--------| | projectKey | 项目唯一标识,对应后端 Project.key | 'BDC' / 'BDCDJ3' / 'BDCYC2' / 'BDCQD' / 'PUB3' | | projectName | 项目名称,首次上报时若项目不存在则自动创建 | '不动产登记中心' | | version | 项目版本号,对应后端 Issue.version | 'v2.0.0' | | server | 后端接口前缀,插件据此拼接 /issues-api/* 地址;为空时使用当前页面域名 | '' / 'http://192.168.1.100:3000' | | token | 必填(与 externalUserInfo 二选一),外部系统传入的 JWT token,用于 loginByToken 免密登录 | 'eyJhbGc...' | | externalUserInfo | 必填(与 token 二选一),外部系统传入的用户信息,用于 loginByUser 免密登录(无 JWT 场景) | { userName: 'admin', userNickname: '管理员' } | | enabled | 是否启用插件 | true(默认) | | autoScreenshot | 接口报错时是否自动截图 | true(默认) | | screenshotMode | 截图模式:off 关闭 / normal 普通(默认)/ precision 精准(需 HTTPS + Chromium);可被系统设置下发覆盖,详见 4.7.4 | 'normal' | | screenshotOptions.delay | 报错后等待多少毫秒再截图,等待错误提示框弹出 | 500 ~ 1000 | | ignore.urls | 忽略的 URL 正则/字符串列表 | [/heartbeat/, /poll/] | | ignore.statusCodes | 忽略的 HTTP 状态码 | [401, 403] | | ignore.businessCodes | 忽略的业务错误码 | ['401', '9999'] | | isBackendEnabled | 是否显示"提交后台"按钮 | true(默认),显式 false 时隐藏 | | backendApiHeaders | 提交到后台时的额外请求头 | { 'x-gisq-token': 'Bearer ...' } | | jsError | 是否监听 window.onerror | true(默认) | | vueError | 是否监听 Vue 错误(需调用 setVueInstance) | 随 setVueInstance 自动开启 | | promiseError | 是否监听未捕获 Promise 拒绝 | true(默认) | | xhrError | 是否拦截 XMLHttpRequest 错误 | true(默认) | | consoleError | 是否拦截 console.error | false(默认,避免噪音) | | resourceError | 是否监听图片/脚本/CSS 加载失败 | true(默认) | | onBugCaptured | Bug 捕获后的回调函数 | (bug) => { ... } | | loadPluginConfig | 异步加载运行时配置的钩子,覆盖默认的 /system-settings/plugin 拉取逻辑 | async () => ({ resourceError: false }) | | setAxiosInstance / setAxiosInstances | 注入 axios 实例;支持单个或数组批量注入多个实例 | axios / [RegAxios, WorkflowAxios] |

6.8 AI Inbox 配置(可选)

const issuesReporter = new IssuesReporter({
  projectKey: 'BDC',
  // ... 其他配置
  aiInbox: {
    enabled: true,
    defaultEmployeeId: '001ai',
    defaultFormat: 'word',
    employees: [
      {
        id: '001ai',
        name: '001号 AI 员工',
        host: '192.168.1.105',
        port: 8765
      }
    ]
  }
})

或在运行时动态注入:

issuesReporter.setAiInboxConfig({
  enabled: true,
  defaultEmployeeId: '001ai',
  defaultFormat: 'word',
  employees: [...]
})

7. 业务背景

本插件服务于 BDC 不动产登记中心 系列子系统,已知子系统包括:

| 项目标识 (projectKey) | 业务范围 | 接入模式 | 关键配置 | |-----------|---------|---------|---------| | BDC | 不动产通用(电子证照、纳税申报、评估报告等) | npm (Vue 3) | delay: 800,忽略证照刷新轮询 | | BDCDJ3 | 登记业务(影像规则、规则检查等) | npm (Vue 3) | delay: 500,忽略规则检查轮询 | | BDCYC2 | 不动产预告 / 转移 / 抵押 / 变更等全流程 | npm (Vue 3) | delay: 1000,忽略流程状态轮询 | | BDCQD | 地籍调查(业务中心配置等) | iframe / npm | delay: 600,忽略地图瓦片加载 | | PUB3 | 智治平台 | npm (Vue 2) | delay: 600,忽略心跳接口 |

HTTP/HTTPS 混合环境: BDC 系统同时存在 HTTP 和 HTTPS,插件服务需部署两套,配置使用 // 协议自适应。

常见 Bug 类型:

  • 表单必填校验缺失(字段标 * 但未校验)
  • 流程步骤间数据传递异常(挂单元重复、数据未刷新)
  • 界面响应异常(无响应、转圈、跳转失败)
  • 国产环境兼容性问题
  • 配置项不生效

8. 目录结构

issues-reporter-plugin/
├── src/                                    # 主应用(调试 / 演示入口)
│   ├── main.ts
│   ├── App.vue
│   ├── router/
│   └── views/
│       └── DemoPage.vue          # 插件演示页
│
├── packages/                               # 插件核心模块
│   ├── core/                               # 📦 核心逻辑层(纯 TS)
│   │   ├── interceptors/
│   │   │   ├── http-interceptor.ts         # HTTP 拦截(axios / fetch)与统一协调
│   │   │   ├── error-classifier.ts         # 错误分类与分级
│   │   │   ├── error-capture.ts            # 统一捕获接口定义
│   │   │   ├── js-error-listener.ts        # JS 运行时错误监听
│   │   │   ├── vue-error-handler.ts        # Vue 2/3 错误处理
│   │   │   ├── promise-error-listener.ts   # Promise 未捕获拒绝监听
│   │   │   ├── xhr-interceptor.ts          # XMLHttpRequest 拦截
│   │   │   ├── console-error-interceptor.ts# console.error 拦截
│   │   │   └── resource-error-listener.ts  # 资源加载错误监听
│   │   ├── services/
│   │   │   ├── screenshot.service.ts       # 截图引擎 Facade(SnapDOM + 调度)
│   │   │   ├── screenshot/
│   │   │   │   ├── image-preprocessor.ts   # 图片等待 + WebGL 画布同帧快照
│   │   │   │   ├── scroll-sync.ts          # 滚动同步
│   │   │   │   ├── iframe-capturer.ts      # iframe 截图合成(Worker 优先)
│   │   │   │   ├── rasterize-client.ts     # Worker 光栅化客户端(编码/压缩/合成移出主线程)
│   │   │   │   ├── storm-guard.ts          # 错误风暴断路器
│   │   │   │   └── precision-capturer.ts   # 精准截图(getDisplayMedia 标签页捕获)
│   │   │   ├── screenshot-idb.store.ts     # 截图 Blob IndexedDB 工作集(写入 + 惰性水合)
│   │   │   ├── bug-builder.service.ts      # Bug 构建器(标准结构)
│   │   │   ├── bug-store.service.ts        # 数据存储(内存)+ Blob 惰性水合/释放
│   │   │   └── export.service.ts           # 导出服务框架
│   │   ├── exporters/
│   │   │   ├── json.exporter.ts
│   │   │   ├── markdown.exporter.ts
│   │   │   ├── csv.exporter.ts
│   │   │   ├── word.exporter.ts
│   │   │   └── pdf.exporter.ts
│   │   └── index.ts
│   │
│   ├── ui/                                 # 📦 UI 层(纯 DOM + TS)
│   │   ├── components/
│   │   │   ├── floating-toolbar.ts         # 悬浮工具栏(原生 DOM)
│   │   │   ├── bug-dialog.ts               # Bug 弹窗容器(原生 DOM)
│   │   │   ├── bug-list.ts                 # Bug 列表组件(原生 DOM)
│   │   │   ├── bug-create.ts               # 创建 Bug 表单(原生 DOM)
│   │   │   ├── export-panel.ts             # 导出面板(原生 DOM)
│   │   │   ├── send-ai-dialog.ts           # 发送 AI 对话框
│   │   │   ├── panels/                     # 弹窗内各面板
│   │   │   │   ├── issue-list-panel.ts     # 模块一:我的问题清单(后端数据)
│   │   │   │   ├── issue-edit-panel.ts     # 问题详情 / 编辑
│   │   │   │   ├── bug-create-panel.ts     # 模块二:创建问题表单
│   │   │   │   ├── bug-preflight-panel.ts  # 创建预检(选取本地 Bug → 提交)
│   │   │   │   ├── bug-list-panel.ts       # 本地 Bug 列表
│   │   │   │   ├── bug-detail-panel.ts     # 本地 Bug 详情
│   │   │   │   ├── bug-export-panel.ts     # 导出面板
│   │   │   │   ├── ai-inbox-panel.ts       # 发送 AI 对话框
│   │   │   │   └── dialog-utils.ts         # 弹窗工具函数
│   │   │   └── annotation-canvas.ts        # 截图标注画布(原生 DOM)
│   │   ├── styles/
│   │   │   ├── toolbar.css                 # 工具栏样式
│   │   │   ├── dialog.css                  # 弹窗样式
│   │   │   ├── list.css                    # 列表样式
│   │   │   └── canvas.css                  # 画布样式
│   │   └── index.ts
│   │
│   ├── adapters/                           # 📦 分发适配层
│   │   ├── npm-adapter.ts                  # npm 模式(完全控制截图)
│   │   └── iframe-adapter.ts               # iframe 模式(postMessage)
│   │
│   ├── types/                              # 📦 类型定义
│   │   ├── bug-report.ts
│   │   ├── config.ts
│   │   └── index.ts
│   │
│   ├── index.ts                            # 统一入口
│   └── auto-init.ts                        # <script> 自动初始化入口
│
├── scripts/                                # 构建与发布脚本
│   ├── release.js                          # 交互式 npm 发布脚本
│   └── chalk.js                            # 命令行日志工具
│
├── ai-inbox-server/                        # AI Inbox 接收服务
│   └── ai-inbox-server.js
│
├── vite.config.ts                          # 主库构建配置
├── vite.auto.config.ts                     # 自动初始化入口构建配置
├── tsconfig.json
└── package.json

9. 开发规范

9.1 代码风格

  • 前端技术栈:TypeScript + 原生 DOM(零框架依赖)
  • 样式:原生 CSS(无预处理器依赖)
  • UI 实现:原生 DOM API(createElementappendChildaddEventListener
  • 接口层:Service 封装,统一管理
  • 组件命名:PascalCase(如 FloatingToolbar
  • 类命名:PascalCase(如 IssuesReporterService
  • 文件名:kebab-case(如 http-interceptor.service.ts

10. 项目目标

核心目标: 固化 Bug 描述标准结构,让下游团队拿到的是可直接复现、信息完整的标准文档,而非模糊的口头描述。

关键指标

  • [ ] 接口报错自动捕获覆盖率 ≥ 95%
  • [ ] 全端异常捕获覆盖率 ≥ 90%(JS / Vue / Promise / XHR / console / resource)
  • [ ] Bug 信息完整度(接口地址 + 入参 + 路由 + 描述 + 截图)≥ 100%
  • [ ] 支持 npm 包 + iframe 两种分发方式
  • [ ] 自动截图 + 手动标注功能可用
  • [ ] 支持 JSON / Markdown / CSV / Word / PDF 五种导出格式
  • [ ] 支持批量勾选导出
  • [ ] 支持导出到局域网 AI 员工 Inbox(JSON / MD / PDF / Word)
  • [ ] 适配 BDC / BDCDJ3 / BDCYC2 / BDCQD / PUB3 五个子系统
  • [ ] 支持 Vue 2 / Vue 3 / React / Angular 项目接入
  • [ ] 支持 HTTP/HTTPS 混合环境

11. 注意事项

  1. 插件作为外部独立模块,不能侵入宿主业务系统的业务逻辑代码,仅通过拦截器 / Hook 机制采集信息。
  2. 截图功能需考虑浏览器兼容性:普通截图基于 SnapDOM(SVG foreignObject,国产信创浏览器基于 Chromium,完美支持);精准截图依赖 getDisplayMedia,仅 HTTPS 安全上下文 + Chromium 系浏览器(Chrome 94+)可用,插件通过特性检测自动隐藏不可用入口。
  3. iframe 模式下需处理跨域通信(postMessage),宿主提供截图钩子,插件调用。
  4. npm 包模式下需提供完善的配置项,适配不同子系统的技术栈差异(Vue 2、Vue 3、React、Angular、纯 JS)。
  5. HTTP/HTTPS 混合环境需部署两套插件服务,配置使用协议自适应(//plugin.example.com)。
  6. 异常捕获模块(XHR / console 等)采用 monkey-patch 时,必须保存原始引用并在 stop() 时精确恢复,避免与宿主业务代码冲突。