jquick-pdf 工单时效报表实战:七次追问,把四条折线画进一页 A4
摘要(meta description):工单 SLA 月报要在一张图里放受理、处理、办结、超期四条时长曲线,量纲相同但量级差三倍。调试过程中我攒了七个问题:最大值为什么必须手动刷新、为什么不用 JLine、系列名和备选名为什么要写两遍、数据标签为什么要关掉、四条线的颜色怎么排、模板里那句 areaBreak 干什么、三月和八月的小反弹是不是画错了。逐条答完,图也就调平了(jquick-pdfx 4.7.0+,Apache-2.0)。
标签 :jquick-pdf、Java PDF、报表开发、折线图
官网示例:
- FORMULAS 示例页:www.jquick.org/jquick-pdf/...
- github 地址:github.com/paohaijiao/...
真实渲染效果预览
以下为上述代码 + 模板真实运行生成的 PDF 首屏预览(由 jquick-pdf 渲染输出,非示意图):

疑问一:那句"必须刷新 Y 轴最大值",到底在干什么
代码里有一行看着很没安全感的调用:
java
// 设置完折线数据后必须刷新 Y 轴最大值
chartData.updateMaxValues();
注释用了"必须"两个字。我第一反应是不刷新会怎样------四条线的最大值是 6.2、9.8、3.6、2.4 这一档,如果不算,纵轴上限可能停在默认刻度上,超期那条线(9.8 起步)就会顶着画布上沿甚至出界。
这套 API 里纵轴上限有两个开关:setAutoCalculateMax(true) 打开"跟着数据算"的模式,updateMaxValues() 是真正执行那次计算。数据是先灌进去的、图是后画的,两者之间没有自动联动,所以顺序是:四条线的数据设完 → 调一次刷新 → 再渲染。我的理解是这一行要放在 setLineDataList(...) 之后、renderChart(...) 之前,位置错了等于没算。
setAutoCalculateMax(true) 和 updateMaxValues() 是配套的,只调其中一个都不完整。这份 Demo 两个都写了,我照着抄,没敢省。
(效果预览图 alt:jquick-pdf 生成的工单处理时效趋势 PDF,粗蓝分隔线的抬头、四条收敛的折线、第二页为季度时效汇总表与六条结论)
疑问二:为什么不用 JLine,偏要 JMultiLineChartData
同一套库里有两个折线类:JLine 和 JMultiLineChartData。差别不在能画几条线------JLine 也能 option.series(a, b) 叠两条。
差别在坐标轴和画布的控制粒度。JLine 走的是 JOption 加 JCategoryAxis、JValueAxis 那套,轴是独立对象,图是系列集合;JMultiLineChartData 把 x 轴标签、y 轴标题、网格数、点半径、文字色、页脚色全收进同一个数据对象,一块配完。
这份报表需要调的东西太多:网格 6 条、内点半径 2、外点半径 5、绘图区底色 248/249/250、轴色纯黑、网格色 220/220/220。用 JLine 那套得在好几个对象之间来回设,JMultiLineChartData 一个对象搞定。四条线共用一套坐标轴的时候,这种"整包配置"的思路更顺手。
代价是它不吃 JCategoryAxis。x 轴标签要单独给:
java
chartData.setXAxisLabels(Arrays.asList("1月", "2月", ..., "12月"));
疑问三:setName 和 setLegendText 为什么各写一遍
java
JMultiLineChartData.LineData lineA = new JMultiLineChartData.LineData();
lineA.setName("平均受理时长");
lineA.setLegendText("平均受理时长(小时)");
两个字段的值几乎一样,区别只在后者多了"(小时)"。这不是冗余设计------name 是系列标识,legendText 是图例上真正显示的文案。图里四条线的单位都是小时,图例写成"平均受理时长(小时)"能省掉读者去 y 轴标题找单位的一次回看;name 保持短名,在别处引用系列名时不至于太长。
四条线的 legendText 都带"(小时)",name 都不带。y 轴标题另给了 setYAxisTitle("时长(小时)"),单位一共出现在三个地方:轴标题、图例、页脚统计口径。这种重复在报表里是必要的,任何一处被裁掉,读者都要多推一步。
LineData 上还有两个参数值得说:setLineWidth(2.5f) 四条线统一 2.5,比常见的 2.0 粗一点。四条线挤在 700pt 宽、380pt 高的画布里,线太细在打印稿上会发虚;2.5 是个折中,再粗线条之间会糊在一起。
疑问四:数据标签关掉,读者靠什么读数
java
chartData.setShowDataLabels(false);
chartData.setValueWithPercent(false);
四个系列、十二条月份、每条线 12 个点,一共 48 个数据标签。全打开的话,图上会糊成一片数字,相邻的点(比如 1.6 和 1.5)标签直接叠在一起,比不标还难读。关掉是对的。
关掉之后读数靠两个东西补。一个是 setGridCount(6) 的横向网格,六条线把纵轴分成若干档,读者按格子估位置,估得出"这条线在 4 小时上下"这种量级,估不出小数点后一位。另一个是第二页的季度汇总表,四个季度加全年平均,20 个精确值全在表里。
图和表分工明确:图看趋势形状------四条线是不是一起往下走、谁降得陡、哪个月有拐点;表看具体数值------一季度办结到底 6.0 还是 5.9。
setValueWithPercent(false) 是另一件事,它管的是数值是否按百分比展示。这份数据的量纲是小时,不是占比,必须关掉。
疑问五:四条线的颜色为什么是蓝、浅蓝、橙、灰
java
lineA.setLineColor(new Color(47, 85, 151)); // 深政务蓝
lineB.setLineColor(new Color(91, 155, 213)); // 浅蓝
lineC.setLineColor(new Color(197, 90, 17)); // 砖橙
lineD.setLineColor(new Color(127, 127, 127)); // 中灰
四条线的语义不一样,颜色得跟着语义走。
受理和处理是同一族指标,都是"环节内耗时",用同色系的深蓝和浅蓝,读者一眼能归组,还能顺着深浅分出主次------受理是入口,给深色。办结是端到端的总耗时,跨部门流转,性质变了,所以跳出蓝色用砖橙,让它从三条蓝线里跳出来。超期那条用中灰,因为它是"异常样本的平均值",不是全体工单的指标,灰色在报表里天然带"次要、参考"的意味,不该和三条主线争。
四条线的位置也有讲究:受理在最下(1.1 到 2.4)、处理其次(1.8 到 3.6)、办结再上(3.1 到 6.2)、超期最高(4.6 到 9.8)。画出来是四条几乎平行的下降曲线,从下往上依次是受理、处理、办结、超期------这个堆叠关系和业务流程的层级是一致的,越往后端耗时越长。
setChartAreaColor(new Color(248, 249, 250)) 给绘图区铺一层几乎看不见的浅灰,比纯白柔和。坐标轴压成纯黑,网格用 220 的浅灰,网格比轴线淡,层次就出来了。
疑问六:模板里那句 areaBreak 是干什么的
html
<div style="marginBottom:10px">...图表区...</div>
<areaBreak></areaBreak>
<div style="marginBottom:10px">...季度汇总表...</div>
areaBreak 是强制分页。这份报表的图表占 700pt 宽、380pt 高,加上抬头和图注,第一页基本满了;表格五行加六条结论再挤上来,结论会被切到第二页中间,非常难看。
Demo 的处理是主动切:图独占第一页,表格和结论从第二页顶上开始。读者翻页的动作和数据的分段对上了------第一页看趋势,第二页看数字和结论。
这个标签在整份模板里只出现一次,位置在图表区和表格区之间。加的时候要留神别加在列表中间,把六条结论切成两半,那比不分页更糟。
模板抬头是另一处值得看的:borderBottom:4px solid #2F5597 一根粗蓝线压在标题下面,标题 19pt,下面一行 flex 左右分栏------左边副标题、右边"统计周期:2024年1月 - 12月 | 单位:小时"。左边交代这张图看什么,右边交代口径,一行两件事。
表格第一列的左边框是 3px 深蓝,其余三边 1px 浅灰:
html
<td style="padding:5px; borderTop:1px solid #DCE3EC; borderRight:1px solid #DCE3EC; borderBottom:1px solid #DCE3EC; borderLeft:3px solid #2F5597">'第一季度'</td>
四行季度加一行全年,第一列左侧都压着这根 3px 的蓝线,五行连起来就是一条竖着的引导线,把读者的视线钉在行首。
疑问七:3 月和 8 月的反弹是真的吗
模板结论里有一句"3月、8月办结时长出现小幅反弹(5.9 / 4.7 小时)"。我对着代码里的数组核了一遍。
办结时长序列:6.2、5.8、5.9 、5.5、5.1、4.8、4.6、4.7、4.3、3.9、3.5、3.1。3 月的 5.9 比 2 月的 5.8 高 0.1,比 4 月的 5.5 高 0.4;8 月的 4.7 比 7 月的 4.6 高 0.1,比 9 月的 4.3 高 0.4。两处确实是局部上翘,整条线整体向下,只有这两处冒出一个小小的尖。
0.1 小时的反弹在图上几乎看不出来,但表格里能读出来。这种"数据里本来就有、但不显眼"的细节要不要写进结论,是个取舍:不写,读者自己发现会怀疑图画错;写了,等于承认流程里有两个卡点。模板选了后者,还给了归因------"与月中集中交办和系统升级窗口重叠"。
我核数的时候还顺手验了季度平均值。一季度受理 (2.4+2.1+1.9)÷3 = 2.13,表里 2.1;处理 (3.6+3.4+3.2)÷3 = 3.4,对;办结 (6.2+5.8+5.9)÷3 = 5.97,表里 6.0;超期 (9.8+9.2+8.6)÷3 = 9.2,对。四季度办结 (3.9+3.5+3.1)÷3 = 3.5,对。全年平均受理 19.6÷12 = 1.63,表里 1.6。
降幅也能对上:办结 6.2 降到 3.1,降 50.0%;超期 9.8 降到 4.6,降 53.1%。两个百分比都没问题。
数字对不上时先查这四处
调这类报表,图和表打架是常态。我踩过的顺序是:先查 x 轴标签和数值数组有没有错位,再查季度平均值是不是按三个月算的,然后查百分比的分母用的是期初还是期末,末了查模板里的硬编码有没有跟着改。
四处里最容易漏的是第四条。这份模板的结论区写死了六条,每条至少一个数字,源数据改一次,这十几处都得过一遍。它不在代码里,IDE 不会提示,只能靠人。
复现清单
- 依赖
io.github.paohaijiao:jquick-pdfx:4.7.0+(Apache-2.0 协议); new JMultiLineChartData(),设 x 轴标签、主副标、y 轴标题、页脚、网格数 6;- 打开
setShowInnerPoint(true),setPointRadius(5)配setInnerPointRadius(2),关掉setShowDataLabels和setValueWithPercent; - 四个
LineData各自setName、setLegendText、setValues、setLineColor、setLineWidth(2.5f),再setLineDataList(...); updateMaxValues()必须在设置完折线之后、渲染之前调用;new JTitle()设主副标后option.setTitle(title),再option.setData(chartData);renderChart(JChartType.MultipleLine, option)取 SVG,bind("svg", svg)后执行report/biz/21_ticket_sla_line.txt;- 验证
D:\test\biz\21_ticket_sla_line.pdf两页结构,核对季度均值与全年均值。
完整源码附录
java
/*
* 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 (goudingcheng@gmail.com)
*/
package com.github.paohaijiao.biz.chart;
import com.github.paohaijiao.JOption;
import com.github.paohaijiao.JTitle;
import com.github.paohaijiao.combol.JMultiLineChartData;
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.Arrays;
import java.util.List;
/**
* 业务场景 Demo 21:工单处理时效趋势(政务服务热线 / 企业工单系统)
*
* <p>业务场景:政务与企业工单系统按月统计受理、处理、办结及超期工单的处理时长,
* 用于服务质量考核与流程优化,主色采用政务蓝 #2F5597。</p>
* <p>实际图表类型:{@link JChartType#MultipleLine} 多重折线图(四条时长指标共用「小时」量纲,观察月度收敛趋势)。</p>
*
* <p>模板:{@code report/biz/21_ticket_sla_line.txt};图表以 SVG 文本形式绑定到模板的
* {@code ${svg}} 占位符,输出到 {@code D:\test\biz\21_ticket_sla_line.pdf}。</p>
*
* <p>图表尺寸说明:图表按 700pt × 380pt(宽 × 高)的横版比例设计;模板中 {@code <svg>}
* 只声明宽度、不声明高度,因此宽度被页面自动收窄时高度会按原比例同步缩放,不会纵向拉伸变形。</p>
*
* @author Martin
* @version 1.0.0
*/
public class JQuickBiz21TicketSlaLineTest {
public static final String path = JQuickConstant.path;
@Test
public void biz21TicketSlaLine() throws IOException {
List<String> months = Arrays.asList("1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月");
JMultiLineChartData chartData = new JMultiLineChartData();
chartData.setXAxisLabels(months);
chartData.setTitleText("2024年工单处理时效趋势");
chartData.setSubtitleText("受理 / 处理 / 办结 / 超期时长月度对比");
chartData.setYAxisTitle("时长(小时)");
chartData.setFooterText("数据来源:工单管理系统 | 统计口径:自然月(单位:小时)");
chartData.setGridCount(6);
chartData.setShowDataLabels(false);
chartData.setShowInnerPoint(true);
chartData.setPointRadius(5);
chartData.setInnerPointRadius(2);
chartData.setChartAreaColor(new Color(248, 249, 250));
chartData.setAxisColor(Color.BLACK);
chartData.setGridColor(new Color(220, 220, 220));
chartData.setTextColor(Color.BLACK);
chartData.setFooterColor(new Color(128, 128, 128));
chartData.setValueWithPercent(false);
chartData.setAutoCalculateMax(true);
chartData.setRotateXAxisLabels(false);
// 平均受理时长:前端智能分派与自助填报推动逐月下降
JMultiLineChartData.LineData lineA = new JMultiLineChartData.LineData();
lineA.setName("平均受理时长");
lineA.setLegendText("平均受理时长(小时)");
lineA.setValues(Arrays.asList(2.4, 2.1, 1.9, 1.8, 1.7, 1.6, 1.6, 1.5, 1.4, 1.3, 1.2, 1.1));
lineA.setLineColor(new Color(47, 85, 151));
lineA.setLineWidth(2.5f);
// 平均处理时长:部门流转与协同处置环节耗时
JMultiLineChartData.LineData lineB = new JMultiLineChartData.LineData();
lineB.setName("平均处理时长");
lineB.setLegendText("平均处理时长(小时)");
lineB.setValues(Arrays.asList(3.6, 3.4, 3.2, 3.0, 2.8, 2.7, 2.6, 2.4, 2.3, 2.1, 2.0, 1.8));
lineB.setLineColor(new Color(91, 155, 213));
lineB.setLineWidth(2.5f);
// 平均办结时长:从受理到办结的端到端耗时(3月、8月出现小幅反弹)
JMultiLineChartData.LineData lineC = new JMultiLineChartData.LineData();
lineC.setName("平均办结时长");
lineC.setLegendText("平均办结时长(小时)");
lineC.setValues(Arrays.asList(6.2, 5.8, 5.9, 5.5, 5.1, 4.8, 4.6, 4.7, 4.3, 3.9, 3.5, 3.1));
lineC.setLineColor(new Color(197, 90, 17));
lineC.setLineWidth(2.5f);
// 超期工单平均超期时长:长尾工单管控效果
JMultiLineChartData.LineData lineD = new JMultiLineChartData.LineData();
lineD.setName("超期工单平均超期时长");
lineD.setLegendText("超期工单平均超期时长(小时)");
lineD.setValues(Arrays.asList(9.8, 9.2, 8.6, 8.1, 7.6, 7.2, 6.8, 6.4, 6.0, 5.5, 5.1, 4.6));
lineD.setLineColor(new Color(127, 127, 127));
lineD.setLineWidth(2.5f);
chartData.setLineDataList(Arrays.asList(lineA, lineB, lineC, lineD));
// 设置完折线数据后必须刷新 Y 轴最大值
chartData.updateMaxValues();
JOption option = new JOption();
JTitle title = new JTitle();
title.setText("2024年工单处理时效趋势");
title.setSubtext("受理 / 处理 / 办结 / 超期时长月度对比");
option.setTitle(title);
option.setData(chartData);
String svg = JChartRendererFactory.renderChart(JChartType.MultipleLine, option);
File dir = new File(path + "biz");
if (!dir.exists()) {
dir.mkdirs();
}
FileOutputStream fileOutputStream = new FileOutputStream(path + "biz/21_ticket_sla_line.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/21_ticket_sla_line.txt");
fileOutputStream.write(bytes);
fileOutputStream.close();
}
}
html
<pdf>
<body>
<div style="marginBottom:12px; borderBottom:4px solid #2F5597; paddingBottom:8px; keepTogether:true">
<h1 style="color:#2F5597; fontSize:19pt; bold:true; marginBottom:4px">'2024年工单处理时效趋势'</h1>
<div style="display:flex; justifyContent:space-between">
<div style="width:290px">
<p style="color:#6c757d; fontSize:9pt">'副标题:受理 / 处理 / 办结 / 超期时长月度对比'</p>
</div>
<div style="width:250px; textAlignment:right">
<p style="color:#6c757d; fontSize:9pt">'统计周期:2024年1月 - 12月 | 单位:小时'</p>
</div>
</div>
</div>
<div style="marginBottom:10px">
<h2 style="color:#2F5597; fontSize:13pt; bold:true; underline:true; marginBottom:6px">'一、处理时效月度走势'</h2>
<div style="display:flex; justifyContent:center">
<svg style="width:700pt">${svg}</svg>
</div>
<p style="fontSize:9pt; color:#6c757d; italic:true; marginTop:6px">'图 1 2024年1-12月受理 / 处理 / 办结 / 超期工单平均时长(数据来源:工单管理系统)'</p>
</div>
<areaBreak></areaBreak>
<div style="marginBottom:10px">
<h2 style="color:#2F5597; fontSize:13pt; bold:true; underline:true; marginBottom:6px">'二、季度时效汇总'</h2>
<table style="width:560px; fontSize:10pt">
<tr>
<th style="width:120px; backgroundColor:#2F5597; color:white; padding:6px; textAlign:center; border:1px solid #DCE3EC">'季度'</th>
<th style="width:110px; backgroundColor:#2F5597; color:white; padding:6px; textAlign:center; border:1px solid #DCE3EC">'受理时长(小时)'</th>
<th style="width:110px; backgroundColor:#2F5597; color:white; padding:6px; textAlign:center; border:1px solid #DCE3EC">'处理时长(小时)'</th>
<th style="width:110px; backgroundColor:#2F5597; color:white; padding:6px; textAlign:center; border:1px solid #DCE3EC">'办结时长(小时)'</th>
<th style="width:110px; backgroundColor:#2F5597; color:white; padding:6px; textAlign:center; border:1px solid #DCE3EC">'超期时长(小时)'</th>
</tr>
<tr>
<td style="padding:5px; borderTop:1px solid #DCE3EC; borderRight:1px solid #DCE3EC; borderBottom:1px solid #DCE3EC; borderLeft:3px solid #2F5597">'第一季度'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'2.1'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'3.4'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'6.0'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'9.2'</td>
</tr>
<tr>
<td style="padding:5px; borderTop:1px solid #DCE3EC; borderRight:1px solid #DCE3EC; borderBottom:1px solid #DCE3EC; borderLeft:3px solid #2F5597">'第二季度'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'1.7'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'2.8'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'5.1'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'7.6'</td>
</tr>
<tr>
<td style="padding:5px; borderTop:1px solid #DCE3EC; borderRight:1px solid #DCE3EC; borderBottom:1px solid #DCE3EC; borderLeft:3px solid #2F5597">'第三季度'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'1.5'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'2.4'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'4.5'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'6.4'</td>
</tr>
<tr>
<td style="padding:5px; borderTop:1px solid #DCE3EC; borderRight:1px solid #DCE3EC; borderBottom:1px solid #DCE3EC; borderLeft:3px solid #2F5597">'第四季度'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'1.2'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'2.0'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'3.5'</td>
<td style="padding:5px; textAlign:right; border:1px solid #DCE3EC">'5.1'</td>
</tr>
<tr>
<td style="padding:6px; bold:true; borderTop:1px solid #DCE3EC; borderRight:1px solid #DCE3EC; borderBottom:1px solid #DCE3EC; borderLeft:3px solid #2F5597">'全年平均'</td>
<td style="padding:6px; textAlign:right; bold:true; border:1px solid #DCE3EC">'1.6'</td>
<td style="padding:6px; textAlign:right; bold:true; border:1px solid #DCE3EC">'2.7'</td>
<td style="padding:6px; textAlign:right; bold:true; border:1px solid #DCE3EC">'4.8'</td>
<td style="padding:6px; textAlign:right; bold:true; border:1px solid #DCE3EC">'7.1'</td>
</tr>
</table>
</div>
<div style="marginBottom:10px">
<h2 style="color:#2F5597; fontSize:13pt; bold:true; underline:true; marginBottom:6px">'三、时效改进结论'</h2>
<list style="listStyleType:disc; paddingLeft:16px; fontSize:10pt">
<li style="marginBottom:5px"><span style="bold:true; color:#2F5597">'端到端时效持续收敛:'</span>'平均办结时长由1月 6.2 小时降至12月 3.1 小时,降幅 50.0%。'</li>
<li style="marginBottom:5px"><span style="bold:true; color:#2F5597">'受理环节提速最明显:'</span>'平均受理时长由 2.4 小时降至 1.1 小时,四季度均值 1.2 小时,为全年最低水平。'</li>
<li style="marginBottom:5px"><span style="bold:true; color:#2F5597">'处理环节稳定下降:'</span>'平均处理时长从 3.6 小时降至 1.8 小时,四季度首次进入 2 小时区间。'</li>
<li style="marginBottom:5px"><span style="bold:true; color:#2F5597">'超期工单管控见效:'</span>'超期工单平均超期时长由 9.8 小时压降至 4.6 小时,降幅 53.1%。'</li>
<li style="marginBottom:5px"><span style="bold:true; color:#2F5597">'波动提示:'</span>'3月、8月办结时长出现小幅反弹(5.9 / 4.7 小时),与月中集中交办和系统升级窗口重叠,建议错峰安排。'</li>
<li style="marginBottom:5px"><span style="bold:true; color:#2F5597">'建议:'</span>'将全年目标设为办结时长不超过 3 小时,并把超期时长纳入部门月度服务质量考核。'</li>
</list>
</div>
<lineSeparator style="strokeColor:#DCE3EC"></lineSeparator>
<div style="display:flex; justifyContent:space-between; marginTop:8px">
<div style="width:180px">
<p style="color:#6c757d; fontSize:8pt">'密级:内部'</p>
</div>
<div style="width:200px; textAlignment:center">
<p style="color:#6c757d; fontSize:8pt">'生成时间:2025年1月10日'</p>
</div>
<div style="width:180px; textAlignment:right">
<p style="color:#6c757d; fontSize:8pt">'批准人:政务服务热线中心主任'</p>
</div>
</div>
</body>
</pdf>