一、前台
1.创建echarts统计图相关
//基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('taskTotal'));//项目统计
//项目统计指定图表的配置项和数据
var initOption = {
title: {
text: '月度计划项目统计图',
x:'center',
y:'top',//标题位置
textAlign:'center'
},
tooltip: {
trigger: 'axis'//鼠标移上图标触发轴
},
legend: {//图例;
data:['计划完成值','实际完成值'],
x:'center',
y:'bottom'//图例位置
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true//坐标轴标签不会溢出容器
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,//左右无留白;
name:'月份',//横轴名称
data: []
},
yAxis: {
type: 'value',
name:'数量'//纵轴名称
},
series: [
{
name:'计划完成值',
type:'line',
stack: '总量2',
symbol: 'circle', //设定为实心点
symbolSize: 10, //设定实心点的大小
itemStyle : {
normal : {
color:'#0099ff' ,//折线点颜色
lineStyle:{
color:'#0099ff' ,//折线条颜色
width:2,
type:'dashed' //'dotted'虚线 'solid'实线
}
}
},
data:[]
},
{
name:'实际完成值',
type:'line',
stack: '总量1',
symbol: 'circle', //设定为实心点
symbolSize: 10, //设定实心点的大小
itemStyle : {
normal : {
lineStyle:{
color:'red',
width:2
}
}
},
data:[]
}
]
};
以上的taskTotal是一个预先准备好id=“taskTotal”的dom,即一个有明确宽高的div区域。
2.给统计图赋值
//项目统计
function taskTotal(unitNames,startDate,endDate){
$.ajax({
url :webCfg.servePath +"/reportForm/showTotalForm",
type: "POST",
dataType : "JSON",
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
data: {"unitNames":encodeURI(unitNames),"startDate":startDate,"endDate":endDate},
cache : false,
beforeSend : function(XHR) {
},
success : function(result) {
//请求成功时处理
var data =result;
if (typeof(data.xAxis) == "undefined"||typeof(data.series) == "undefined"){
initOption.xAxis.data = [];//x轴
initOption.series[0].data = [];
initOption.series[1].data = [];
}else{
//initOption.legend.data = data.legend;
initOption.xAxis.data = data.xAxis;//x轴
var serieslist = data.series;
for (var i = 0; i < serieslist.length; i++) {//循环放入数据
initOption.series[i].data = serieslist[i];
}
}
myChart.setOption(initOption, true);
var common=$("#taskTotal").parent();//该表单的父节点
//页面表单回显
common.find("input[name='startTime']").val(data.echoes.startTime);
common.find("input[name='endTime']").val(data.echoes.endTime);
common.find("input[name='unitNames']").val(data.echoes.unitNames);
//给报表表格添加内容;
var html ="";
if(data.xAxis!= null && typeof data.xAxis !== "undefined" && data.xAxis.length>0){
for(var i=0;i<data.xAxis.length;i++){
html+="<tr>";
html+="<td width='6%'>"+(i+1)+"</td>";
html+="<td>"+data.xAxis[i]+"</td>";
html+="<td>"+data.xAxis[i]+"</td>";
html+="<td>"+(data.series[0])[i]+"</td>";
html+="<td>"+(data.series[1])[i]+"</td>";
html+="</tr>";
}
}else{
html ="<tr><td colspan='99' style='text-align:center'>查询数据为空</td></tr>";
}
common.find("tbody").empty();
common.find("tbody").append(html);
},
complete : function() {
//请求完成的处理
},
error : function(e) {
//请求出错处理
alert(e);
}
});
}
赋值数据通过请求后台得到,这里省略(按需要补充)。
3.js以post方式提交统计报表数据
//点击导出按钮获取到导出Excel的相关数据
function btnExcel() {
var picBaseCode=myChart.getDataURL();
//获取报表上存在的条件
var unitNames=nodeCommon.find("input[name='unitNames']").val();
var startDate=nodeCommon.find("input[name='startTime']").val();
var endDate=nodeCommon.find("input[name='endTime']").val();
var status=nodeCommon.find("input[name='status']").val();
var delayNum=nodeCommon.find("input[name='delayNum']").val();
//调用方法请求后台;
reportExcel(index+1,picBaseCode,unitNames,startDate,endDate,status,delayNum);
}
//封装待导出Excel的参数
function reportExcel(reportType,picBaseCode,unitNames,startDate,endDate,status,delayNum){
var url=webCfg.servePath +"/reportForm/reportExcel";
var params = {
"reportType":reportType,
"picBaseCode":picBaseCode,
"unitNames":encodeURI(unitNames),
"startDate":startDate,
"endDate":endDate,
"status":encodeURI(status),
"delayNum":encodeURI(delayNum)
};
httpPost(url, params);
}
//发送POST请求跳转到指定页面
function httpPost(URL, PARAMS) {
var temp = document.createElement("form");
temp.action = URL;
temp.method = "post";
temp.style.display = "none";
for (var x in PARAMS) {
var opt = document.createElement("textarea");
opt.name = x;
opt.value = PARAMS[x];
temp.appendChild(opt);
}
document.body.appendChild(temp);
temp.submit();
return temp;
}
二、后台
/**
* 导出报表
*
* @return
*/
@RequestMapping(value = "/reportExcel", method = RequestMethod.POST)
public Object getReportExcel(HttpServletRequest request, HttpServletResponse response) throws Exception {
fileName = "项目统计表.xlsx";
OutputStream os=response.getOutputStream();
setFileName(request, response, fileName);//设置导出文件标题及编码
// 第一步,创建一个HSSFWorkbook,对应一个Excel文件
// 创建Excel工作薄
Workbook book = null;
try {
book = new XSSFWorkbook();//excell2007
} catch (Exception ex) {
book = new HSSFWorkbook();//excell2003
}
// 第二步,在workbook中添加一个sheet,对应Excel文件中的sheet
Sheet sheet = book.createSheet(fileName);
//调用方法获取统计报表内的表格数据(此处省略,需自行补充,同前台echarts统计图数据源)
@SuppressWarnings("unchecked")
Map<String, Object> result = (Map<String, Object>) taskTotalForm(request);
String[] xAxis = (String[]) result.get("xAxis");
@SuppressWarnings("unchecked")
List<Integer[]> series = (List<Integer[]>) result.get("series");
// 第三步,设置标题和表头;
Row row = sheet.createRow(0);// 创建第一行,设置表的标题;
row.setHeightInPoints(36);//设置行的高度是34个点
Cell cell = row.createCell(0);
cell.setCellValue(headTitle);
sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, cols - 1));//第一行跨表所有列;
// 第二行为表头行
String title = "";
Row row1 = sheet.createRow(1);// 创建第2行
row1.setHeightInPoints(22);//设置表头行的高度是20个点
for (int i = 0; i < 4; i++) {
Cell cell = row1.createCell(i);
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
if (i == 0) {
title = "月份";
}
if (i == 1) {
title = "时间节点";
}
if (i == 2) {
title = "计划完成项";
}
if (i == 3) {
title = "实际完成项";
}
cell.setCellValue(title);
}
int start = 2;
//根据各一级任务的分解任务数循环向单元格填充数据;
for (int i = 0; i < xAxis.length; i++) {
Row row = sheet.createRow(start + i);
Cell cell0 = row.createCell(0);
Cell cell1 = row.createCell(1);
Cell cell2 = row.createCell(2);
Cell cell3 = row.createCell(3);
cell0.setCellValue(xAxis[i]);
cell1.setCellValue(xAxis[i]);
cell2.setCellValue(series.get(0)[i]);
cell3.setCellValue(series.get(1)[i]);
}
//生成统计图图片
String imgUrl = request.getParameter("picBaseCode");
if (!imgUrl.isEmpty()) {
String[] imgUrlArr = imgUrl.split("base64,");//拆分base64编码后部分
byte[] buffer = new BASE64Decoder().decodeBuffer(imgUrlArr[1]);
//获取项目运行目录的路径:以下是request.getRealPath()的代替方法
String picPath = request.getSession().getServletContext().getRealPath(
"static/app/appkmbgszh/images" + fileName + ".png");
File file = new File(picPath);//图片文件
try {
//生成图片
OutputStream out = new FileOutputStream(file);//图片输出流
out.write(buffer);
out.flush();//清空流
out.close();//关闭流
// 将图片写入流中
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
BufferedImage bufferImg = ImageIO.read(file);
ImageIO.write(bufferImg, "PNG", outStream);
// 利用HSSFPatriarch或XSSFDrawing将图片写入EXCEL
Drawing patri = sheet.createDrawingPatriarch();
//偏移量 这个有点恶心, 这个单位直接以万 计, 10000以下 基本设了等于没设。原因不明 ,操作2003 的 HSSF 是正常的比例
ClientAnchor anchor = new XSSFClientAnchor(30 * 10000, 0, 100, 100, 5, 1, 18, 22);
patri.createPicture(anchor, book.addPicture(outStream.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG));
// 写入数据 把相应的Excel 工作簿存盘
book.write(os);
book.close();
os.close();
} catch (Exception ex) {
ex.printStackTrace();
}
if (file.exists()) {
file.delete();//删除图片
}
}
}
/**
* 设置导出文件名,并处理编码问题;
* @param request
* @param response
* @param name
* @throws UnsupportedEncodingException
*/
public void setFileName(HttpServletRequest request, HttpServletResponse response, String name)
throws UnsupportedEncodingException {
String agent = request.getHeader("USER-AGENT");
if (null != agent && -1 != agent.indexOf("MSIE") || null != agent && -1 != agent.indexOf("Trident")) {// IE
name = java.net.URLEncoder.encode(name, "UTF8");
} else if (null != agent && -1 != agent.indexOf("Mozilla")) {// 火狐,chrome等
name = new String(name.getBytes("UTF-8"), "iso-8859-1");
}
response.setHeader("Content-disposition", "attachment; filename=" + name);
}
三、说明
关于HSSFClientAnchor(dx1,dy1,dx2,dy2,col1,row1,col2,row2)的参数,有必要在这里说明一下: dx1:起始单元格的x偏移量,如例子中的255表示直线起始位置距A1单元格左侧的距离; dy1:起始单元格的y偏移量,如例子中的125表示直线起始位置距A1单元格上侧的距离; dx2:终止单元格的x偏移量,如例子中的1023表示直线起始位置距C3单元格左侧的距离; dy2:终止单元格的y偏移量,如例子中的150表示直线起始位置距C3单元格上侧的距离; col1:起始单元格列序号,从0开始计算; row1:起始单元格行序号,从0开始计算,如例子中col1=0,row1=0就表示起始单元格为A1; col2:终止单元格列序号,从0开始计算; row2:终止单元格行序号,从0开始计算,如例子中col2=2,row2=2就表示起始单元格为C3;