本次技术改造涉及三个前端项目:bi-webreport-web 和公共组件库 g-components,旨在优化 BI Summary 类图表的自定义报告导出流程。以下为具体实现思路及部分细节说明:

改造后的流程与细节

一、数据传输及图表绘制流程

  1. 触发导出任务(report-web

    • 用户在 report-web 发起图表导出请求,携带图表任务信息及初始数据。
  2. 加载 iframe 并监听消息(report-web

    • 使用 iframe 加载 bi-web 内指定的页面 /onedata/report-iframe
    • 在 iframe 加载完成(load 事件触发)后,report-web 立即在主页面注册 message 事件监听,监听 iframe 发来的消息。

二、iframe 页面数据处理与交互(bi-web

  1. 页面初始化与消息监听

    • iframe 页面挂载完成(mounted事件)后,通过 window.addEventListener('message', messageHandler) 注册监听 message 消息事件。
    • 向父窗口发送 MessageType.Mounted 类型消息,通知父页面准备就绪:

      window.parent.postMessage({ type: MessageType.Mounted, source: 'bi-report' }, '*');
  2. 数据接收与图表渲染

    • 接收到父页面(report-web)发送的原始图表数据后(消息事件类型为数据本身),调用图表组件进行数据设置和渲染:

      iframeRef.value.contentWindow.postMessage(props.data, '*');
  3. 组件数据处理(GTable

    • 在公共组件库 g-componentsGTable 组件中,封装了 AntV/S2 表格组件。
    • 在组件实例中新增方法 getFormattedTableData,利用 AntV 原生的 copyData 方法,获取经格式化后的表格数据(以制表符 \t 分隔)。
    • 在组件的 onMounted 生命周期事件中监听 S2Event.LAYOUT_AFTER_RENDER 事件,以确保表格渲染完成后再调用获取格式化数据方法。
    • 获取到格式化数据后,通过传入的回调函数 onFinished 将数据回传给 iframe 主页面:

      instance.on(S2Event.LAYOUT_AFTER_RENDER, () => {
      const formattedData = instance.getFormattedTableData();
      props.onFinished(formattedData);
      });
  4. 返回最终数据给父窗口

    • iframe 主页面接收到格式化数据后,通过消息传递回父页面(report-web):

      window.parent.postMessage({
      type: MessageType.PaintFinished,
      source: 'bi-report',
      data: formattedData
      }, '*');

三、最终数据导出与消费

  1. report-web 数据消费

    • report-web 接收到 MessageType.PaintFinished 消息及数据后,将该数据保存在全局变量中。
    • 后端服务通过轮询该全局变量,获取最终格式化后的表格数据,用于后续导出或其他业务场景。

流程图(Mermaid时序图)

2025-05-29-17.26.54.webp

sequenceDiagram
    participant ReportWeb
    participant Iframe(bi-web)
    participant GTable(g-components)

    ReportWeb->>Iframe(bi-web): load /onedata/report-iframe
    Iframe(bi-web)-->>ReportWeb: MessageType.Mounted
    ReportWeb->>Iframe(bi-web): 回传原始数据(data)
    Iframe(bi-web)->>GTable(g-components): setData(data)
    GTable(g-components)-->>Iframe(bi-web): onFinished(formattedData)
    Iframe(bi-web)-->>ReportWeb: MessageType.PaintFinished(formattedData)
    ReportWeb->>Backend: 轮询获取formattedData完成导出

通过上述技术方案,显著优化了数据导出流程,提高了前端组件之间的数据交互效率和数据导出准确性。

原始笔记

涉及到3个前端项目:
bi-web、report-web和g-components

本次改造的表格类图表的自定义报告打印全流程:
1. report-web收到打某个图表的任务和数据
2. 新建iframe打开bi-web的页面(/onedata/report-iframe)
    1. 在页面mounted事件回调中通过window.addEventListener('message', messageHandler); 添加’message’事件监听和处理回调,在这个回调中,根据情况(将data字符串作为key从indexDB取数据或data直接就是所需数据)设置图表绘制时所需要的数据,触发图表绘制。改造后的GTable(from g-components公共组件库)在暴露出来的实例中新增了getFormattedTableData方法通过s2/antv表格组件的原生copyData方法获取格式化后的表格数据,可以在GTable的onMounted事件回调中添加S2Event.LAYOUT_AFTER_RENDER事件监听,并在回调中使用getFormattedTableData获取最终所需的格式化后的图表数据字符串(分隔符为’t’),并调用一开始传给图表绘制组件的onFinished回调函数,把数据传进去,供bi-web的iframe根页面消费(会调用handleFinishedWithData方法,通过window.parent.postMessage({ type: MessageType.PaintFinished, source: 'bi-report', data }, ‘*’); 将最终数据发送给report-web供其消费)
    2. 通过window.parent.postMessage({ type: MessageType.Mounted, source: 'bi-report' }, ‘*’); 发送MessageType.Mounted类型的信息给report-web父页面,让其把图表原始数据通过一个新的消息发回bi-web的iframe
3. iframe的load事件触发onIframeLoaded方法,添加’message’事件(postMessage跨iframe传递消息)监听,在回调中根据消息type进行不同的处理:
    1. MessageType.Mounted:通过iframeRef.value.contentWindow.postMessage(props.data, ‘*’);将图表绘制所需的原始数据通过消息传递给bi-web的iframe页面供其消费
    2. MessageType.PaintFinished:接收事件参数中的 格式化后的最终所需要的表格数据,并传给该类型图表的onFinished回调函数供其消费(将数据放在全局变量中供后端服务轮询获取,流程结束)

A Student on the way to full stack of Web3.