跳转到内容

Java 生成「告警数量周趋势时间线(应急 / 运维平台)」PDF 示例(TimeLine)

JQuick-PdfBiz Demo

TimeLine1 页 A4 · 121 KB

按周统计告警数量并用时间线呈现,直观展示告警高峰与处置节奏。

下载 PDF 文件查看模板原始文件返回全部示例

告警数量周趋势时间线(应急 / 运维平台) — TimeLine
渲染效果

输出规格

PDF 页数
1
图表类型
TimeLine
模板行数
98
源码行数
96

Java 源码 · JQuickBiz36AlertWeekTimelineTest.java

以下代码即生成上方 PDF 的完整测试类,可直接复制运行;Maven 依赖见快速开始章节。

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright (c) [2025-2099] Martin ([email protected])
 */
package com.github.paohaijiao.demo.biz;

import com.github.paohaijiao.JOption;
import com.github.paohaijiao.combol.JTimeLineData;
import com.github.paohaijiao.config.JPdfConfig;
import com.github.paohaijiao.demo.constant.JQuickConstant;
import com.github.paohaijiao.enums.JChartType;
import com.github.paohaijiao.executor.JQuickPdfFactory;
import com.github.paohaijiao.factory.JChartRendererFactory;
import org.junit.Test;

import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 业务场景 Demo 36:告警数量周趋势时间线(应急/运维平台)
 *
 * <p>业务场景:应急指挥平台按周汇总去重后的告警数量,展示第1周至第8周的趋势与周环比,用于运维值班复盘。</p>
 * <p>实际图表类型:{@link JChartType#TimeLine} 时间线,每个节点标注当周告警数量与环比变化,
 * 节点颜色按主色由深到浅依次过渡。</p>
 *
 * <p>模板:{@code report/biz/36_alert_week_timeline.txt};图表以 SVG 文本形式绑定到模板的
 * {@code ${svg}} 占位符,输出到 {@code D:\test\biz\36_alert_week_timeline.pdf}。</p>
 *
 * <p>图表尺寸说明:时间线渲染器画布为横向宽图(1300×500 比例);模板中 {@code <svg>} 只声明宽度、
 * 不声明高度,宽度被页面自动收窄时高度会按原比例同步缩放,不会纵向拉伸变形。</p>
 *
 * @author Martin
 * @version 1.0.0
 */
public class JQuickBiz36AlertWeekTimelineTest {

    public static final String path = JQuickConstant.path;

    @Test
    public void biz36AlertWeekTimeline() throws IOException {
        JTimeLineData data = new JTimeLineData();
        List<JTimeLineData.FlowNode> nodes = new ArrayList<>();
        // 8 个节点,颜色按 #BF360C 主色系由深到浅过渡;节点文字用「|」分隔成两行
        nodes.add(new JTimeLineData.FlowNode("第1周", "告警 328 起|环比 +6.5%", new Color(191, 54, 12), new Color(191, 54, 12)));
        nodes.add(new JTimeLineData.FlowNode("第2周", "告警 296 起|环比 -9.8%", new Color(198, 76, 40), new Color(198, 76, 40)));
        nodes.add(new JTimeLineData.FlowNode("第3周", "告警 341 起|环比 +15.2%", new Color(216, 112, 74), new Color(216, 112, 74)));
        nodes.add(new JTimeLineData.FlowNode("第4周", "告警 305 起|环比 -10.6%", new Color(224, 140, 108), new Color(224, 140, 108)));
        nodes.add(new JTimeLineData.FlowNode("第5周", "告警 278 起|环比 -8.9%", new Color(232, 168, 142), new Color(232, 168, 142)));
        nodes.add(new JTimeLineData.FlowNode("第6周", "告警 352 起|环比 +26.6%", new Color(240, 196, 176), new Color(240, 196, 176)));
        nodes.add(new JTimeLineData.FlowNode("第7周", "告警 389 起|环比 +10.5%", new Color(246, 214, 200), new Color(246, 214, 200)));
        nodes.add(new JTimeLineData.FlowNode("第8周", "告警 334 起|环比 -14.1%", new Color(250, 228, 218), new Color(250, 228, 218)));
        data.setNodes(nodes);
        data.setMainTitle("ALERT WEEKLY TREND");
        data.setSubtitle("2024年第1-8周告警数量趋势");
        data.setFooterText("数据来源:应急指挥平台 | 统计口径:去重后告警数");
        data.setHeight(1300);
        data.setBoxWidth(200);
        data.setBoxHeight(90);
        data.setStartX(100);
        data.setEndX(100);
        JOption option = new JOption();
        option.setData(data);

        String svg = JChartRendererFactory.renderChart(JChartType.TimeLine, option);

        File dir = new File(path + "biz");
        if (!dir.exists()) {
            dir.mkdirs();
        }
        FileOutputStream fileOutputStream = new FileOutputStream(path + "biz/36_alert_week_timeline.pdf");
        JPdfConfig config = new JPdfConfig();
        // 开启 flex 行布局,使模板中的 display:flex 生效(图表居中)
        config.getLayoutConfig().setFlexLayout(true);
        JQuickPdfFactory factory = new JQuickPdfFactory(config);
        factory.bind("svg", svg);
        byte[] bytes = factory.executeResource("report/biz/36_alert_week_timeline.txt");
        fileOutputStream.write(bytes);
        fileOutputStream.close();
    }
}

最小调用(3 行)

不想读完整测试类?核心就是这三行:绑定图表 SVG,执行模板,拿到 PDF 字节流。可直接复制到你的项目里。

// config 可省略;svg 来自 JChartRendererFactory.renderChart(...),见下方完整源码
factory.bind("svg", svg);
byte[] pdf = new JQuickPdfFactory(config).executeResource("report/biz/36_alert_week_timeline.txt");

模板文件 · 36_alert_week_timeline.txt

类 HTML + 内联 CSS 的模板语法,绑定数据后渲染为 PDF。下方为完整模板,可直接复制,也可下载原始文件。

<pdf>
<body>
  <div style="marginBottom:10px; padding:10px; backgroundColor:#FDF0EA; borderTop:3px solid #BF360C; borderRadius:4px">
    <h2 style="color:#BF360C; marginTop:0; marginBottom:6px; fontSize:15; bold:true; textAlignment:center">'告警数量周趋势时间线'</h2>
    <p style="fontSize:9; color:#6c757d; textAlignment:center; marginBottom:8px">'统计周期:2024年第1周 - 第8周 | 数据来源:应急指挥平台(去重后告警数)'</p>
    <div style="display:flex; justifyContent:space-between; marginBottom:4px">
      <div style="width:285px">
        <div style="display:flex; justifyContent:center">
          <svg style="width:285px">${svg}</svg>
        </div>
        <p style="fontSize:8; color:#6c757d; textAlignment:center; marginTop:4px">'图 1  第1-8周告警数量与环比变化'</p>
      </div>
      <div style="width:265px">
        <h3 style="color:#BF360C; fontSize:12; bold:true; marginBottom:6px">'趋势要点'</h3>
        <list style="listStyleType:disc; paddingLeft:14px; fontSize:9">
          <li style="marginBottom:5px">'八周告警合计 2,623 起,周均 328 起,整体呈高位震荡、无持续恶化。'</li>
          <li style="marginBottom:5px">'第5周 278 起为八周最低,第7周 389 起为最高,峰谷差 111 起。'</li>
          <li style="marginBottom:5px">'上升周与下降周各 4 周,环比波动区间为 -14.1% 至 +26.6%。'</li>
          <li style="marginBottom:5px">'第6周环比 +26.6% 为最大增幅,与批量新设备入网时间点吻合。'</li>
        </list>
      </div>
    </div>
  </div>

  <h2 style="color:#BF360C; fontSize:13; bold:true; borderBottom:1px solid #BF360C; paddingBottom:3px; marginBottom:8px">'一、周度告警明细'</h2>
  <div style="marginBottom:12px">
    <table style="width:540px; fontSize:10">
      <tr>
        <th style="width:120px; backgroundColor:#BF360C; color:white; padding:6px; textAlign:center; border:1px solid #F3D3C4">'周次'</th>
        <th style="width:140px; backgroundColor:#BF360C; color:white; padding:6px; textAlign:center; border:1px solid #F3D3C4">'告警数(起)'</th>
        <th style="width:140px; backgroundColor:#BF360C; color:white; padding:6px; textAlign:center; border:1px solid #F3D3C4">'环比'</th>
        <th style="width:140px; backgroundColor:#BF360C; color:white; padding:6px; textAlign:center; border:1px solid #F3D3C4">'累计告警(起)'</th>
      </tr>
      <tr>
        <td style="padding:5px; border:1px solid #F3D3C4">'第1周'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'328'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'+6.5%'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'328'</td>
      </tr>
      <tr>
        <td style="padding:5px; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'第2周'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'296'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'-9.8%'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'624'</td>
      </tr>
      <tr>
        <td style="padding:5px; border:1px solid #F3D3C4">'第3周'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'341'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'+15.2%'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'965'</td>
      </tr>
      <tr>
        <td style="padding:5px; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'第4周'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'305'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'-10.6%'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'1,270'</td>
      </tr>
      <tr>
        <td style="padding:5px; border:1px solid #F3D3C4">'第5周'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'278'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'-8.9%'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'1,548'</td>
      </tr>
      <tr>
        <td style="padding:5px; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'第6周'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'352'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'+26.6%'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'1,900'</td>
      </tr>
      <tr>
        <td style="padding:5px; border:1px solid #F3D3C4">'第7周'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'389'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'+10.5%'</td>
        <td style="padding:5px; textAlign:right; border:1px solid #F3D3C4">'2,289'</td>
      </tr>
      <tr>
        <td style="padding:5px; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'第8周'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'334'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'-14.1%'</td>
        <td style="padding:5px; textAlign:right; backgroundColor:#FDF0EA; border:1px solid #F3D3C4">'2,623'</td>
      </tr>
    </table>
  </div>

  <h2 style="color:#BF360C; fontSize:13; bold:true; borderBottom:1px solid #BF360C; paddingBottom:3px; marginBottom:8px">'二、值班复盘要点'</h2>
  <list style="listStyleType:disc; paddingLeft:16px; fontSize:10">
    <li style="marginBottom:6px"><span style="bold:true; color:#BF360C">'峰值周:'</span>'第7周告警 389 起,为八周最高,环比 +10.5%,主要来自强降雨期间设备离线告警集中上报。'</li>
    <li style="marginBottom:6px"><span style="bold:true; color:#BF360C">'谷值周:'</span>'第5周告警 278 起,为八周最低,环比 -8.9%,得益于节前专项巡检提前消除隐患。'</li>
    <li style="marginBottom:6px"><span style="bold:true; color:#BF360C">'连续回落:'</span>'第4至第5周告警由 305 起降至 278 起,两周累计下降 8.9%,同期处置及时率稳步提升。'</li>
    <li style="marginBottom:6px"><span style="bold:true; color:#BF360C">'月末反弹:'</span>'第6至第7周告警由 352 起升至 389 起,累计上升 10.5%,主因是批量新设备入网带来的阈值误报。'</li>
    <li style="marginBottom:6px"><span style="bold:true; color:#BF360C">'建议:'</span>'复核第6至第7周的告警规则,压降误报比例,并将周告警量目标控制在 320 起以内。'</li>
  </list>

  <lineSeparator style="strokeColor:#DCE3EC"></lineSeparator>
  <p style="color:#6c757d; fontSize:8; marginTop:8px">'数据来源:应急指挥平台 | 统计口径:去重后告警数 | 生成时间:2024年9月2日'</p>
</body>
</pdf>

同分组示例

本页 PDF、预览图、模板与源码均由 JQuick-Pdf 真实运行产出,可自由复制到你的项目中使用。