告别ASP.NET操作EXCEL的烦恼(总结篇)

本文转自:http://www.cnblogs.com/peaceli/archive/2008/04/13/1151520.html

 

      公元19XX年前,关于EXCEL的操作就如滔滔江水,连绵不绝,真正操作EXCEL我也是从去年下半年开始的,有些比较复杂的年度报表之类 的,做起来也有点费力,不过还是都能画出来了,关于EXCEL的报表导出,考虑到导出耗时的问题我主要采用AJAX来做的,分别捕捉几个起止状态,给客户 端提示3个状态:正在检索数据。。。---》准备导出数据。。。(只是从数据库成功取出,还没有读写excel文件)--》正在读写文件--》导出数据成 功,当然如果哪一过程出错,都有对应的提示,只所以想到写这篇文章,主要是因为今年有个系统的部分EXCEL的操作也让我做,顺便结合之前操作EXCEL 的经验作一下总结,可能也算不上什么,对于绝大多数来说也没什么技术含量,网上一搜一大把,但我想还是有必要总结一下,至少能给园子里的新手些许帮 助,OK,Let's Go...

   一. 程序操作EXCEL的应用主要还是在统计报表方面,您可能会考虑读EXCEL模板,也可能会考虑没必要读模板,其实读不读模板都能达到一样的效果,看实际情况而用了。
       1. 读模板的话,首先模板存放在某个路径下,根据模板把从数据库里取出的数据写回EXCEL然后生成一个新的EXCEL存放都另一个路径以供下载,模板不变。
          我这里的EXCEL操作主要是在VS2005里的,VS2003也可以的,不过没怎么研究03里的操作(文章最后我会把05的示例下载地址贴上 那个demo里之前打包忘了放了一个生成数据的文件,刚放进去了,不加也是可以运行的,还有模板文件的数据稍微过滤了下重新放了部分对照看下 )vs05中操作EXCEL直接引用.NET自带的COM组件

的bin目录下会自动出现

Interop.Excel.dll这个DLL(需安装office2003 excel,下面的说明及示例都是基于office2003的,版本不同调用可能会不一样)
页面的命名空间引用 using Excel;
下面是调用模板的一段代码

 1     #region  使用模板导出Excel表
 2                    case   " ReportByTemp " :
 3                       {
 4  
 5                           DataView dv  =  Cache[ " ReportByTemp " as  DataView;
 6                            // 建立一个Excel.Application的新进程
 7                           Excel.Application app  =   new  Excel.Application();
 8                            if  (app  ==   null )
 9                           {
10                                return ;
11                           }
12                           app.Visible  =   false ;
13                           app.UserControl  =   true ;
14                           Workbooks workbooks  =  app.Workbooks;
15                           _Workbook workbook  =  workbooks.Add(template_path  +   " //EXCEL测试模板.xls " ); // 这里的Add方法里的参数就是模板的路径
16                           Sheets sheets  =  workbook.Worksheets;
17                           _Worksheet worksheet  =  (_Worksheet)sheets.get_Item( 1 ); // 模板只有一个sheet表
18                            if  (worksheet  ==   null )
19                           {
20                                return ;
21                           }
22  
23                            int  rowNum  =   0 ;
24                            for  ( int  i  =   0 ; i  <  dv.Count; i ++ )
25                           {
26                               rowNum  =  i  +   1 ;
27                               worksheet.Cells[ 3   +  i,  1 =  rowNum;
28                               worksheet.Cells[ 3   +  i,  2 =  dv[i].Row[ 0 ].ToString();
29                               worksheet.Cells[ 3   +  i,  3 =  dv[i].Row[ 1 ].ToString();
30  
31                               excelOperate.SetBold(worksheet, worksheet.Cells[ 3   +  i,  1 ], worksheet.Cells[ 3   +  i,  1 ]);  // 黑体
32                               excelOperate.SetHAlignCenter(worksheet, worksheet.Cells[ 3   +  i,  1 ], worksheet.Cells[ 3   +  i,  3 ]); // 居中
33                               worksheet.get_Range(worksheet.Cells[ 3   +  i,  1 ], worksheet.Cells[ 3   +  i,  3 ]).Borders.Color  =  System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
34  
35                           }
36  
37                           tick  =  DateTime.Now.Ticks.ToString();
38                           save_path  =  temp_path  +   " // "   +  tick  +   " .xls " ;
39                           workbook.SaveAs(save_path, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Excel.XlSaveAsAccessMode.xlNoChange, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
40                           excelOperate.Dispose(worksheet, workbook, app); // 关闭Excel进程
41  
42                       }
43                        break ;
44                    #endregion

效果如下:

       2. 不读模板的话,调用的时候其实会继承一个空白模板,然后写入数据,程序画表头,最终达到一样的效果,程序如下:

 1     #region  不使用模板生成Excel表
 2                    case   " ReportByNone " :
 3                       {
 4  
 5                           DataView dv  =  Cache[ " ReportByNone " as  DataView;
 6                            // 建立一个Excel.Application的新进程
 7                           Excel.Application app  =   new  Excel.Application();
 8                            if  (app  ==   null )
 9                           {
10                                return ;
11                           }
12                           app.Visible  =   false ;
13                           app.UserControl  =   true ;
14                           Workbooks workbooks  =  app.Workbooks;
15                           _Workbook workbook  =  workbooks.Add(XlWBATemplate.xlWBATWorksheet); // 这里的Add方法里的参数就相当于继承了一个空模板(暂这样理解吧)
16                           Sheets sheets  =  workbook.Worksheets;
17                           _Worksheet worksheet  =  (_Worksheet)sheets.get_Item( 1 );
18                            if  (worksheet  ==   null )
19                           {
20                                return ;
21                           }
22  
23                           worksheet.get_Range(worksheet.Cells[ 1 1 ], worksheet.Cells[ 1 3 ]).Merge(Missing.Value);  // 横向合并
24                           worksheet.get_Range(worksheet.Cells[ 1 1 ], worksheet.Cells[ 1 1 ]).Value2  =   " 导出EXCEL测试一 " ;
25                           excelOperate.SetBold(worksheet, worksheet.Cells[ 1 1 ], worksheet.Cells[ 1 1 ]);  // 黑体
26                           excelOperate.SetHAlignCenter(worksheet, worksheet.Cells[ 1 1 ], worksheet.Cells[ 1 1 ]); // 居中
27                           excelOperate.SetBgColor(worksheet, worksheet.Cells[ 1 1 ], worksheet.Cells[ 1 1 ], System.Drawing.Color.Red); // 背景色
28                           excelOperate.SetFontSize(worksheet, worksheet.Cells[ 1 1 ], worksheet.Cells[ 1 1 ],  16 ); // 字体大小
29                           excelOperate.SetRowHeight(worksheet, worksheet.Cells[ 1 1 ], worksheet.Cells[ 1 1 ],  32.25 ); // 行高
30                           worksheet.get_Range(worksheet.Cells[ 1 1 ], worksheet.Cells[ 1 1 ]).Borders.Color  =  System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black); // 黑色连续边框
31  
32                           worksheet.Cells[ 2 1 =   " 序号 " ;
33                           worksheet.Cells[ 2 2 =   " 公司 " ;
34                           worksheet.Cells[ 2 3 =   " 部门 " ;
35                           excelOperate.SetBold(worksheet, worksheet.Cells[ 2 1 ], worksheet.Cells[ 2 3 ]);  // 黑体
36                           worksheet.get_Range(worksheet.Cells[ 2 1 ], worksheet.Cells[ 2 3 ]).Borders.Color  =  System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
37                           excelOperate.SetHAlignRight(worksheet, worksheet.Cells[ 2 1 ], worksheet.Cells[ 2 3 ]);
38                           excelOperate.SetBgColor(worksheet, worksheet.Cells[ 2 1 ], worksheet.Cells[ 2 3 ], System.Drawing.Color.Silver); // 背景色
39                            int  rowNum  =   0 ;
40                            for  ( int  i  =   0 ; i  <  dv.Count; i ++ )
41                           {
42                               rowNum  =  i  +   1 ;
43                               worksheet.Cells[ 3   +  i,  1 =  rowNum;
44                               worksheet.Cells[ 3   +  i,  2 =  dv[i].Row[ 0 ].ToString();
45                               worksheet.Cells[ 3   +  i,  3 =  dv[i].Row[ 1 ].ToString();
46  
47                               excelOperate.SetBold(worksheet, worksheet.Cells[ 3   +  i,  1 ], worksheet.Cells[ 3   +  i,  1 ]);  // 黑体
48                               excelOperate.SetHAlignCenter(worksheet, worksheet.Cells[ 3   +  i,  1 ], worksheet.Cells[ 3   +  i,  3 ]); // 居中
49                               worksheet.get_Range(worksheet.Cells[ 3   +  i,  1 ], worksheet.Cells[ 3   +  i,  3 ]).Borders.Color  =  System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black); // 设置边框颜色,不然打印预览,会非常不雅观
50  
51                           }
52                           excelOperate.SetColumnWidth(worksheet,  " A " 10 );
53                           excelOperate.SetColumnWidth(worksheet,  " B " 20 );
54                           excelOperate.SetColumnWidth(worksheet,  " C " 20 );
55                           worksheet.Name  =   " 导出EXCEL测试一 " ;
56  
57                           tick  =  DateTime.Now.Ticks.ToString();
58                           save_path  =  temp_path  +   " // " +  tick  +   " .xls " ;
59                           workbook.SaveAs(save_path, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Excel.XlSaveAsAccessMode.xlNoChange, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
60                           excelOperate.Dispose(worksheet, workbook, app); // 关闭Excel进程
61  
62                       }
63                        break ;
64  
65                    #endregion

效果如下:

以上我给了两个最简单的操作说明,下面详细说一下对于一些稍微复杂的报表的生成处理

      二. 对于复杂的EXCEL报表的生成处理,无非是纵向合并相同的数据行及嵌套纵向合并等一些操作,下面就几个具有针对性的报表作下说明.
            1.要生成相对复杂的EXCEL表,在从数据库取数据时,要注意先按照合理的要求排好序,有时候可能order by后面要跟好几个字段,而且这几个字段谁先谁后也要注意,因为这些会直接影响报表呈现的效果,比如你的EXCEL表要按月份统计国内外的项目,显示出来 的时候要多个项目相同的人连续,那么排序就可能要这样order by 月份,项目类别,用户ID,项目ID(这是写好的视图,基于视图来检索的),这个排序的字段顺序就不能变了,变了的话就不太好生成想要的形式了,如下图:

这个也是动态画的,用了个简单的模板,模板就一个表头,没多大意义,除非表头很复杂而且在列表中不需要重画,考虑模板就比较好,向上面那个一月份国际的和 其它月份的都是需要重画表头的。至于合并,如果不是嵌套的合并,我们可以在向模板循环写数据的时候直接控制,比如下面一个简单的写法:

 1     for  (i  =   0 ; i  <  table.Rows.Count; i ++ )
 2                               {
 3                                   bidName  =  table.Rows[index][ " BIDNAME " ].ToString();
 4                                    if  (table.Rows[i][ " BIDNAME " ].ToString()  ==  bidName)
 5                                   {
 6                                       projNum ++ ;
 7                                       worksheet.Cells[ 5   +  i,  2 =  table.Rows[i][ " PROJNO " ];
 8                                       worksheet.Cells[ 5   +  i,  3 =  table.Rows[i][ " PROJNAME " ];
 9                                       worksheet.Cells[ 5   +  i,  4 =  table.Rows[i][ " STAT_DATE " ];
10                                       worksheet.Cells[ 5   +  i,  5 =  table.Rows[i][ " PROJTYPE " ];
11                                       worksheet.Cells[ 5   +  i,  6 =  table.Rows[i][ " CONTENT " ];
12                                       worksheet.Cells[ 5   +  i,  7 =  table.Rows[i][ " OPENDT " ];
13                                       worksheet.Cells[ 5   +  i,  8 =  table.Rows[i][ " OPENADDRESS " ];
14                                       worksheet.Cells[ 5   +  i,  9 =  table.Rows[i][ " REV_DATE " ];
15                                       worksheet.Cells[ 5   +  i,  10 =  table.Rows[i][ " BID_UNIT " ];
16                                       worksheet.Cells[ 5   +  i,  11 =  table.Rows[i][ " AGT_AMOUNT " ];
17                                       worksheet.Cells[ 5   +  i,  12 =  table.Rows[i][ " CURRENCY " +   " : "   +  table.Rows[i][ " BIDSER_AMOUNT " ];
18                                       worksheet.Cells[ 5   +  i,  13 =  table.Rows[i][ " SENDDATE " ];
19                                       worksheet.Cells[ 5   +  i,  14 =  table.Rows[i][ " CURRENCY " +   " : "   +  table.Rows[i][ " BIDPRICE " ];
20                                       worksheet.Cells[ 5   +  i,  15 =  table.Rows[i][ " BOOKAMOUNT " ];
21                                       worksheet.Cells[ 5   +  i,  16 =  table.Rows[i][ " CURRENCY " +   " : "   +  table.Rows[i][ " BAIL_AMOUNT " ];
22                                       worksheet.Cells[ 5   +  i,  17 =  table.Rows[i][ " USERNAME " ];
23                                       worksheet.Cells[ 5   +  i,  18 =  table.Rows[i][ " SECOND_USER " ];
24                                       worksheet.Cells[ 5   +  i,  19 =   "" ;
25                                       worksheet.get_Range(worksheet.Cells[ 5   +  i,  1 ], worksheet.Cells[ 5   +  i,  19 ]).Borders.Color  =  System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
26                                        continue ;
27                                   }
28  
29                                   worksheet.get_Range(worksheet.Cells[ 5   +  rowid,  1 ], worksheet.Cells[ 5   +  i  -   1 1 ]).Merge(Missing.Value);  // 将第一列按投标单位合并
30                                   worksheet.get_Range(worksheet.Cells[ 5   +  rowid,  1 ], worksheet.Cells[ 5   +  rowid,  1 ]).Value2  =  bidName  +   " ( "   +  projNum.ToString()  +   " 个项目) " ; // 合并后的单元格内容

合并单元格的时候也要注意一个问题,就是合并的单元格必须是为空的,不然在执行合并时,会提示“合并后的单元格的值将丢失”,具体不这样提示的,大致是这 个意思,一般我们合并都单元格相同的内容,在合并前我们先保存那个值,再清空后合并,上面的代码中把worksheet.Cell[5+rowid,1] 这里系列的单元格的值空出来了,没写数据,而且最后合并了再写值,避免了去循环清空。
     2.嵌套的合并向上面那样做可能控制比较麻烦,而且思路可能很混乱,我们可以考虑先循环填充所有的数据,在循环出来要合并的列,比如像下面的这张表

先循环填充数据,如下:

 1     int  index  =   0 , rownum  =   0 ;
 2                                string  ProjNo  =   "" ;
 3                                for  (i  =   0 ; i  <  table.Rows.Count; i ++ )
 4                               {
 5                                   ProjNo  =  table.Rows[index][ " PROJNO " ].ToString();
 6                                    if  (table.Rows[i][ " PROJNO " ].ToString()  ==  ProjNo)
 7                                   {
 8                                       wksheet.Cells[ 3   +  i,  1 =  rownum  +   1 ;
 9                                       wksheet.Cells[ 3   +  i,  2 =   " ' "   +  table.Rows[i][ " PROJNO " ];    // 加上单引号保证以0开头的字符原样输出
10                                       wksheet.Cells[ 3   +  i,  3 =   " ' "   +  table.Rows[i][ " PROJNAME " ];
11                                       wksheet.Cells[ 3   +  i,  4 =   " ' "   +  table.Rows[i][ " PA_NAME " ];
12                                       wksheet.Cells[ 3   +  i,  5 =   " ' "   +  table.Rows[i][ " BIDER_NAME " ];
13                                       wksheet.Cells[ 3   +  i,  6 =  table.Rows[i][ " BAIL_AMOUNT " ];
14                                       wksheet.Cells[ 3   +  i,  7 =  table.Rows[i][ " NOT_BACK " ];
15                                       wksheet.get_Range(wksheet.Cells[ 3   +  i,  1 ], wksheet.Cells[ 3   +  i,  7 ]).Borders.Color  =  System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
16                                        continue ;
17                                   }
18  
19                                   index  =  i;
20                                   rownum ++ ;
21                                   i -- ;
22  
23                               }

下面合并前三列相同内容的单元:

 1     // 合并前三列操作
 2                                int  m  =   1 , rowid  =   3 , k;
 3                                string  projName  =   "" ;
 4                                for  (k  =   3 ; k  <=  i  +   2 ; k ++ )
 5                               {
 6                                    if  (Convert.ToInt32(wksheet.get_Range(wksheet.Cells[k,  1 ], wksheet.Cells[k,  1 ]).Value2)  ==  m)
 7                                   {
 8                                       ProjNo  =  wksheet.get_Range(wksheet.Cells[k,  2 ], wksheet.Cells[k,  2 ]).Value2.ToString();
 9                                       projName  =  wksheet.get_Range(wksheet.Cells[k,  3 ], wksheet.Cells[k,  3 ]).Value2.ToString();
10                                       wksheet.get_Range(wksheet.Cells[k,  1 ], wksheet.Cells[k,  1 ]).Value2  =   "" ;
11                                       wksheet.get_Range(wksheet.Cells[k,  2 ], wksheet.Cells[k,  2 ]).Value2  =   "" ;
12                                       wksheet.get_Range(wksheet.Cells[k,  3 ], wksheet.Cells[k,  3 ]).Value2  =   "" ;
13                                        continue ;
14                                   }
15                                   wksheet.get_Range(wksheet.Cells[rowid,  1 ], wksheet.Cells[k  -   1 1 ]).Merge(Missing.Value);
16                                   wksheet.get_Range(wksheet.Cells[rowid,  1 ], wksheet.Cells[rowid,  1 ]).Value2  =  m;
17  
18                                   wksheet.get_Range(wksheet.Cells[rowid,  2 ], wksheet.Cells[k  -   1 2 ]).Merge(Missing.Value);
19                                   wksheet.get_Range(wksheet.Cells[rowid,  2 ], wksheet.Cells[rowid,  2 ]).Value2  =   " ' "   +  ProjNo;
20  
21                                   wksheet.get_Range(wksheet.Cells[rowid,  3 ], wksheet.Cells[k  -   1 3 ]).Merge(Missing.Value);
22                                   wksheet.get_Range(wksheet.Cells[rowid,  3 ], wksheet.Cells[rowid,  3 ]).Value2  =   " ' "   +  projName;
23  
24                                   m ++ ;
25                                   rowid  =  k;
26                                   k -- ;
27                               }
28                                // 跳出循环后合并最后一个招标项目
29  
30                               wksheet.get_Range(wksheet.Cells[rowid,  1 ], wksheet.Cells[k  -   1 1 ]).Merge(Missing.Value);
31                               wksheet.get_Range(wksheet.Cells[rowid,  1 ], wksheet.Cells[rowid,  1 ]).Value2  =  m;
32  
33                               wksheet.get_Range(wksheet.Cells[rowid,  2 ], wksheet.Cells[k  -   1 2 ]).Merge(Missing.Value);
34                               wksheet.get_Range(wksheet.Cells[rowid,  2 ], wksheet.Cells[rowid,  2 ]).Value2  =   " ' "   +  ProjNo;
35  
36                               wksheet.get_Range(wksheet.Cells[rowid,  3 ], wksheet.Cells[k  -   1 3 ]).Merge(Missing.Value);
37                               wksheet.get_Range(wksheet.Cells[rowid,  3 ], wksheet.Cells[rowid,  3 ]).Value2  =   " ' "   +  projName;

下面合并标段列

 1     // 合并标段列
 2  
 3                               index  =   0 ; rowid  =   3 // 重置变量
 4                                string  pa_name  =   string .Empty;  // 标段名称
 5                                for  (k  =   3 ; k  <=  i  +   2 ; k ++ )
 6                               {
 7                                   pa_name  =  table.Rows[index][ " PA_NAME " ].ToString();
 8                                    if  (wksheet.get_Range(wksheet.Cells[k,  4 ], wksheet.Cells[k,  4 ]).Value2.ToString()  ==  pa_name)
 9                                   {
10                                       wksheet.get_Range(wksheet.Cells[k,  4 ], wksheet.Cells[k,  4 ]).Value2  =   "" ;
11                                        continue ;
12                                   }
13                                   wksheet.get_Range(wksheet.Cells[rowid,  4 ], wksheet.Cells[k  -   1 4 ]).Merge(Missing.Value);
14                                   wksheet.get_Range(wksheet.Cells[rowid,  4 ], wksheet.Cells[rowid,  4 ]).Value2  =   " ' "   +  pa_name;
15                                   index  =  k  -   3 ;
16                                   rowid  =  k;
17                                   k -- ;
18  
19                               }
20                                // 退出循环时合并最后一个项目的标段
21                               wksheet.get_Range(wksheet.Cells[rowid,  4 ], wksheet.Cells[k  -   1 4 ]).Merge(Missing.Value);
22                               wksheet.get_Range(wksheet.Cells[rowid,  4 ], wksheet.Cells[rowid,  4 ]).Value2  =   " ' "   +  pa_name;
23                               tick  =  DateTime.Now.ToString( " yyyyMMddhhmmss " );
24                               save_path  =  temp_path  +   " // "   +  tick  +   " 保证金收退情况表.xls " ;
25                               Session[ " BailBackID " =  tick  +   " 保证金收退情况表.xls " ;
26                               Session[ " _BailBack " =   " true " ;
27                               workbook.SaveAs(save_path, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Excel.XlSaveAsAccessMode.xlNoChange, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
28                               excelOperate.Dispose(worksheet, workbook, app); // 关闭Excel进程
29                                // DownLoad(save_path);
30                                // Page_Close();

当然,上面的操作中会进行好几次循环,在性能方面不太可取,园子里的兄弟也许会有更好的方法,小弟不吝赐教了
下面我们看下几个效果图:

 

整个过程采用AJAX提示的,一来不刷新,二来导出时间比较长的话,可以给客户一个良好的体验效果,否可,用户一点导出按钮,半天没反应也没提示,客户就觉得怎么这么慢的,是不是你们程序有问题,指责一大堆,有了这么些交互提示信息,让客户多等几分钟也能承受。

     3.生成的表格包含多个sheet的操作,比如下面一种情况

 

 

绘制这张表的要求是根据选择某年的几月到几月,生成这个几个月的一个综合情况的sheet,然后分别生成这几个月的单独的sheet表,生成上面表的模 板,包含两个sheet ,一个综合月份的sheet和一个单独月份的sheet,因为单独月份的sheet表现形式都是一样的,我们可以根据选择的月份个数Copy几个 sheet就可以了

 1    Workbooks workbooks  =  app.Workbooks;
 2  
 3                               _Workbook workbook  =  workbooks.Add(template_path  +   " //招标单位年度招标情况逐月统计表.xls " );
 4                               Sheets sheets  =  workbook.Worksheets;
 5                               _Worksheet Yearsheet  =  (_Worksheet)sheets.get_Item( 1 );
 6                               _Worksheet worksheet  =  (_Worksheet)sheets.get_Item( 2 );
 7                                if  (worksheet  ==   null )
 8                               {
 9                                    return ;
10                               }
11                                for  ( int  i  =   1 ; i  <  monthCount; i ++ )
12                                   worksheet.Copy(Missing.Value, workbook.Worksheets[ 2 ]); // 月统计工作薄


Yearsheet 的操作就不说了,和前面几个一样操作,关键是月份的sheet的生成,其实就是循环操作get_Item(i),代码如下

 1     //////////////////////////////////// //每月详细统计 ////////////////////////////////////
 2  
 3                                int  item_id  =   2 ;
 4                               rowNum  =   0 ; book_Amount  =   0 ; index  =   0 ;
 5                               bid_Amount  =   "" ; bidser_Amount  =   "" ; agent_Amount  =   0 ; // 清空变量
 6                               _Worksheet ws  =   null ;
 7                                for  ( int  i  =   0 ; i  <  tableMM.Rows.Count; i ++ )
 8                               {
 9                                   rowNum ++ ;
10                                   Month  =  tableMM.Rows[index][ " DATE_MONTH " ].ToString();
11                                    if  (tableMM.Rows[i][ " DATE_MONTH " ].ToString()  ==  Month)
12                                   {
13                                       ws  =  (_Worksheet)sheets.get_Item(item_id);
14                                       ws.Cells[ 3   +  rowNum  -   1 1 =  rowNum;
15                                       ws.Cells[ 3   +  rowNum  -   1 2 =  tableMM.Rows[i][ " PROJNO " ];
16                                       ws.Cells[ 3   +  rowNum  -   1 3 =  tableMM.Rows[i][ " PROJNAME " ];
17                                       ws.Cells[ 3   +  rowNum  -   1 4 =  tableMM.Rows[i][ " BID_TYPE " ];
18                                       ws.Cells[ 3   +  rowNum  -   1 5 =  tableMM.Rows[i][ " BID_MODE " ];
19                                       ws.Cells[ 3   +  rowNum  -   1 6 =  tableMM.Rows[i][ " OPENDT " ];
20                                       ws.Cells[ 3   +  rowNum  -   1 7 =  tableMM.Rows[i][ " OPENADDRESS " ];
21                                       ws.Cells[ 3   +  rowNum  -   1 8 =  tableMM.Rows[i][ " BID_UNIT " ];
22                                       ws.Cells[ 3   +  rowNum  -   1 9 =  tableMM.Rows[i][ " NOTICE_NO " ].ToString().Replace( " 神华国贸 " "" );
23                                       ws.Cells[ 3   +  rowNum  -   1 10 =  tableMM.Rows[i][ " BOOKAMOUNT " ];
24                                       ws.Cells[ 3   +  rowNum  -   1 11 =  tableMM.Rows[i][ " BIDPRICE " +   " (万 "   +  tableMM.Rows[i][ " CURRENCY " +   " ) " ;
25                                       ws.Cells[ 3   +  rowNum  -   1 12 =  tableMM.Rows[i][ " BIDSER_AMOUNT " +   " (万 "   +  tableMM.Rows[i][ " CURRENCY " ] + " ) " ;
26                                       ws.Cells[ 3   +  rowNum  -   1 13 =  tableMM.Rows[i][ " AGT_AMOUNT " ];
27                                       ws.Cells[ 3   +  rowNum  -   1 14 =   "" ;
28                                       ws.get_Range(ws.Cells[ 3   +  rowNum  -   1 1 ], ws.Cells[ 3   +  rowNum  -   1 14 ]).Borders.Color  =  System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
29                                        continue ;
30                                   }
31  
32                                   ws.Cells[ 1 1 =  year  +   " "   +  bidName  +  GetMonth(Month)  +   " 月份招标项目情况一览表 " ;
33  
34                                    // 每月合计
35                                   sql  =   "  SELECT CURRENCY, NVL(SUM(BIDPRICE),0) AS BIDPRICE,NVL(SUM(BOOKAMOUNT),0) AS BOOKAMOUNT,NVL(SUM(BIDSER_AMOUNT),0) AS BIDSER_AMOUNT,NVL(SUM(AGT_AMOUNT),0) AS AGT_AMOUNT FROM IBS_V_BID_MONTHLY_STAT "   +  SqlFilter  +
36                                               "  AND DATE_YEAR =' "   +  year  +   " ' AND COMPANY_ID= "   +  biderID  +   "  AND DATE_MONTH =' "   +  Month  +   " ' "   +
37                                               "  GROUP BY CURRENCY " ;
38                                   System.Data.DataTable dt1  =  OracleHelper.RetDataTable(sql);
39                                    for  ( int  m  =   0 ; m  <  dt1.Rows.Count; m ++ )
40                                   {
41                                       bid_Amount  +=  dt1.Rows[m][ " BIDPRICE " +   " (万 " + dt1.Rows[m][ " CURRENCY " +   " )/r/t " ;
42                                       book_Amount  +=   float .Parse(dt1.Rows[m][ " BOOKAMOUNT " ].ToString());
43                                       bidser_Amount  +=  dt1.Rows[m][ " BIDSER_AMOUNT " +   " (万 "   +  dt1.Rows[m][ " CURRENCY " +   " )/r/t " ;
44                                       agent_Amount  +=   float .Parse(dt1.Rows[m][ " AGT_AMOUNT " ].ToString());
45                                   }
46  
47                                   ws.Cells[ 3   +  rowNum  -   1 3 =   " 合  计 " ;
48                                   ws.Cells[ 3   +  rowNum  -   1 10 =  book_Amount;
49                                   ws.Cells[ 3   +  rowNum  -   1 11 =  bid_Amount;
50                                   ws.Cells[ 3   +  rowNum  -   1 12 =  bidser_Amount;
51                                   ws.Cells[ 3   +  rowNum  -   1 13 =  agent_Amount;
52                                   ws.get_Range(ws.Cells[ 3   +  rowNum  -   1 1 ], ws.Cells[ 3   +  rowNum  -   1 14 ]).Borders.Color  =  System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Black);
53                                   ws.Name  =  GetMM(Month);
54  
55                                   item_id ++ ;
56                                   index  =  i;  // 汇总下一个月份的招标项目
57                                   i -- ;
58                                   rowNum  =   0 ; book_Amount  =   0 ;
59                                   bid_Amount  =   "" ; bidser_Amount  =   "" ; agent_Amount  =   0 ; // 清空变量
60                               }
61  
62                                // 跳出循环时进行最后一个月份的项目汇总

用的是oracle数据库,所以上面那个sql语句。。。 呵呵

============================================================================================
上面大致说得就差不多了,因为是不断循环的什么的,可能对于大的数据量读写来说,比较好性能,如果大家有什么更好的方法,可以指点下,为了弥补等待时间过长,所以才结合了AJAX来处理。

最后我把做的一个小demo的链接帖出来给大家,还有一些空模板和对应生成的数据表给大家对照看下,尤其相对复杂一些的表画应该是能画出来的,主要看大家采用什么样的方法,能少循环一次就尽量少循环,呵呵~~~
   EXCEL模板读写说明
   http://www.justlike.com.cn/upfiles/template_xls.rar
   http://www.justlike.com.cn/upfiles/ExcelFiles.rar
   http://www.justlike.com.cn/upfiles/ExcelReportDemo.rar
(说明:最后弹出下载文件的一个页面一直想让其自动关掉,但是不行,如果不关掉,再点导出,不会弹出下载框,实际的处理中我们可以在导出旁边放个下载按 钮,就像上面的效果图里那样,当然可以点导出的时候让其在网页中直接打开,点下载的时候再弹出下载框,但是直接打开的话,文件需要生成在虚拟目录下,不太 安全,呵呵~~,看实际情况处理了)

==========================================================================================
今天补充说明下,关于那个调用ajax回调的效果,有个地方用到了所谓的“ajax嵌套调用”,如下

 1     function  ExcelReportCallback(resp)
 2    {
 3          if (resp.value  ==   " OK " )
 4         {
 5              
 6                $( ' tipMsg').innerHTML = "& lt;img border=/"0/" src=/"images/s_progressbar.gif/">< font color=#FF0000 style=font-weight:bold>准备导出数据,请稍等 </font>";
 7                setTimeout( " RedirectUrl() " , 1000 ); // 延时体验  
 8         }
 9          else
10           if (resp.value  ==   " NO " )
11          {
12             $( ' tipMsg').innerHTML = "<font color=#FF0000 style=font-weight:bold>没有找到符合该查询条件的数据</font>";
13             $( ' btnExcel').disabled = false;
14          }
15          else
16         {
17             $( ' tipMsg').innerHTML = "<font color=#FF0000 style=font-weight:bold>警告:导出数据出错</font>";
18             $( ' btnExcel').disabled = false;
19         }
20          
21         
22    }

 

 1   function  RedirectUrl()
 2    {
 3        $( ' tipMsg').innerHTML = "& lt;img border=/"0/" src=/"images/ajaxloading.gif/">< font color=#7fffd4 style=font-weight:bold>正在读写报表文件,请稍后 </font>";
 4           var ajax  =   new  ajax_request( " ExcelReport.aspx?flag=ReportByTemp& " + Math.random(),  "" "" , ReportCallback); 
 5            function  ReportCallback(resp)
 6           {
 7                if (resp.value ! =   " Error "   &&  resp.value ! = "" )
 8               {
 9                  $( ' btnExcel').disabled = false;
10                  $( ' tipMsg').innerHTML = "<font color=#FF0000 style=font-weight:bold>数据导出成功!</font>";
11                  Open( " XLS_DownLoad.aspx?path= " + resp.value); // window.location.href  =  resp.value; //
12               }
13                else
14               {
15                  $( ' btnExcel').disabled = false;
16                  $( ' tipMsg').innerHTML = "<font color=#FF0000 style=font-weight:bold>文件读写出错,请检查文件模板是否存在或对文件是否有读写权限!</font>";
17               }
18           }
19  
20    }
21    
22     function  Open(url) 
23   {
24       window.open(url, ' newwindow','height=1,width=1,top=1500,left=1500,toolbar=no,menubar=no,scrollbars=yes,location=no,status=no')
25   }

ExcelReportCallback(resp) 原本是一个回调函数,但是里面调用了一个RedirectUrl() 方 法,这个方法又包含了一个回调函数,这样就形成了回调的嵌套,之所以这么做,是因为,第一个回调是处理从数据库取出数据成功与否,如果成功了跳转到画 EXCEL的页面,这样的话会出现一个空白页等生成好后出现下载框,后来觉得是否可以嵌套一个回调来继续一次异步操作,这样就不会出现长时间等待的空白页 面了,而是生成好EXCEL后返回地址,或者可以返回一个文件名到XLS_DownLoad.aspx 页面直接下载,但是XLS_DownLoad.aspx 也是要出现的,我尝试过让下载后这个页面自动关闭,无赖做不到,所以把Open()方法里的数据值调得让页面不显示,但是状态栏还是有显示的。

到这里算是写完了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值