最近的工作中,要解决web报表的一系列问题。在客户端,我们利用delphi的ie浏览器组件,开发了一个报表容器,对报表进行数据录入、保存、和申报等操作,部分报表数据操作行为可以离线使用。同时,也要求报表也可以直接通过浏览器进行在线访问和操作。
原来我们的web报表系统是以web页面为中心的,一张报表一个独立页面。事实上,可能多张报表之间有公式计算关系,这样如果一张报表的某个字段值改变了,可能会引起其它报表字段值的改变。原有的以页面为中心的模式,不能很好的解决这个问题。
基于以上的需求,把各个有公式关系的报表作为一套报表,或者视为一个报表对象,以json来表示报表的数据,通过js公式解析器,来解析提前定义好的报表公式关系,并把值更新到当前显示的报表页面和json中。这样,后续对报表数据的处理,就完全以json为中心,可以通过delphi调用js,把报表数据持久化到客户端,同时也可以通过ajax的方式,把报表数据提交到java服务器端进行处理。
其实对报表的处理的核心就是对数据的处理,在我们这种模式中,就是对json的处理。而报表关系的核心,就是公式,用户在操作报表数据时,程序根据预先定义的公式,同时对当前显示的web报表页面报表json中的数据值进行修改。
下边给出测试代码。
json报表数据及公式的定义(testJson.js):
// 报表数据json表示 var testJson = { sb_zcfzb1:{ sb_zcfzb_ncs_1:"0.00",sb_zcfzb_ncs_2:"0.00",sb_zcfzb_ncs_3:"0.00",sb_zcfzb_ncs_4:"0.00",sb_zcfzb_ncs_5:"0.00",sb_zcfzb_ncs_6:"0.00", sb_zcfzb_ncs_7:"0.00",sb_zcfzb_ncs_8:"0.00",sb_zcfzb_ncs_9:"0.00",sb_zcfzb_ncs_10:"0.00",sb_zcfzb_ncs_11:"0.00",sb_zcfzb_ncs_12:"0.00", sb_zcfzb_ncs_13:"0.00",sb_zcfzb_ncs_14:"0.00" }, sb_zcfzb2:{ sb_zcfzb_ncz_1:"0.00",sb_zcfzb_ncz_2:"0.00",sb_zcfzb_ncz_3:"0.00" } }; // 报表公式关系表示 var testFormular = { sb_zcfzb1:"sb_zcfzb1.sb_zcfzb_ncs_14^$sb_zcfzb1.sb_zcfzb_ncs_1+$sb_zcfzb1.sb_zcfzb_ncs_2+$sb_zcfzb1.sb_zcfzb_ncs_3+$sb_zcfzb1.sb_zcfzb_ncs_4+$sb_zcfzb1.sb_zcfzb_ncs_5+$sb_zcfzb1.sb_zcfzb_ncs_6+$sb_zcfzb1.sb_zcfzb_ncs_7+$sb_zcfzb1.sb_zcfzb_ncs_8+$sb_zcfzb1.sb_zcfzb_ncs_9+$sb_zcfzb1.sb_zcfzb_ncs_10+$sb_zcfzb1.sb_zcfzb_ncs_11+$sb_zcfzb1.sb_zcfzb_ncs_12+$sb_zcfzb1.sb_zcfzb_ncs_13#4", sb_zcfzb2:"sb_zcfzb2.sb_zcfzb_ncz_1^$sb_zcfzb1.sb_zcfzb_ncs_1+$sb_zcfzb1.sb_zcfzb_ncs_2-$sb_zcfzb1.sb_zcfzb_ncs_3#1," +"sb_zcfzb2.sb_zcfzb_ncz_2^$sb_zcfzb1.sb_zcfzb_ncs_1*$sb_zcfzb1.sb_zcfzb_ncs_2-$sb_zcfzb1.sb_zcfzb_ncs_3," +"sb_zcfzb2.sb_zcfzb_ncz_3^$sb_zcfzb1.sb_zcfzb_ncs_1-$sb_zcfzb1.sb_zcfzb_ncs_2*$sb_zcfzb1.sb_zcfzb_ncs_3#3" };
公式解析计算器的定义及web报表页面及json公式的触发(test.js)
// 引用公式解析计算器 var calculator = tohot.commons.declaration.ExpressionCalculator; calculator.report = testJson; // 设置页面报表公式触发 function setFormular() { sb_zcfzb1.sb_zcfzb_ncs_1.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_1',sb_zcfzb1.sb_zcfzb_ncs_1.value,testFormular.sb_zcfzb1,'2');"); sb_zcfzb1.sb_zcfzb_ncs_2.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_2',sb_zcfzb1.sb_zcfzb_ncs_2.value,testFormular.sb_zcfzb1,'2')");; sb_zcfzb1.sb_zcfzb_ncs_3.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_3',sb_zcfzb1.sb_zcfzb_ncs_3.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_4.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_4',sb_zcfzb1.sb_zcfzb_ncs_4.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_5.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_5',sb_zcfzb1.sb_zcfzb_ncs_5.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_6.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_6',sb_zcfzb1.sb_zcfzb_ncs_6.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_7.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_7',sb_zcfzb1.sb_zcfzb_ncs_7.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_8.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_8',sb_zcfzb1.sb_zcfzb_ncs_8.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_9.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_9',sb_zcfzb1.sb_zcfzb_ncs_9.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_10.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_10',sb_zcfzb1.sb_zcfzb_ncs_10.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_11.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_11',sb_zcfzb1.sb_zcfzb_ncs_11.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_12.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_12',sb_zcfzb1.sb_zcfzb_ncs_12.value,testFormular.sb_zcfzb1,'2')"); sb_zcfzb1.sb_zcfzb_ncs_13.onblur = new Function("calculator.doCalculateCurr('sb_zcfzb1.sb_zcfzb_ncs_13',sb_zcfzb1.sb_zcfzb_ncs_13.value,testFormular.sb_zcfzb1,'2')"); } // 实际情况下,该函数是在保存报表数据之前被调用 function setJson() { // 根据公式定义,计算json值 calculator.doCalculateJson(testFormular); // 遍历json,显示报表数据 for(var key in testJson){ for(var key1 in testJson[key]){ alert(key + "." + key1 + "=" + testJson[key][key1]); } } }
html测试页面(test.html)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>XXX表</title> <link href="css/css.css" rel="stylesheet" type="text/css"> <script language=javascript src="json2.js"></script> <script language="javascript" src="tohot.commons.declaration.ExpressionCalculator.js"></script> <script language=javascript src="testJson.js"></script> <script language=javascript src="test.js"></script> </head> <body onload="javascript:setFormular();"> <form method="post" id="sb_zcfzb1" name="sb_zcfzb1"> <div class="reportTable" style="width:1000px"> <table cellspacing="1" id="reportTable"> <tr class="reportTableTitle"> <td width="20%" rowspan="2" class="report_top_left">资产<br></td> <td width="4%" rowspan="2" class="report_top_middle">行<br>次<br></td> <td width="13%" class="report_top_middle">年初数<br></td> </tr> <tr class="reportTableTitle"> <td class="report_middle_middle"> </td> <td class="report_middle_middle"> </td> <td class="report_middle_middle"> </td> <td class="report_middle_middle"> </td> </tr> <tr> <td class="report_middle_left">流动资产:<br></td> <td class="report_middle_middle"> </td> <td class="report_middle_middle">-<br></td> </tr> <tr> <td class="report_blank_left2">货币资金<br></td> <td class="report_middle_middle">1</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_1" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_1" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">短期投资<br></td> <td class="report_middle_middle">2</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_2" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_2" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">应收票据<br></td> <td class="report_middle_middle">3</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_3" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_3" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">应收股利<br></td> <td class="report_middle_middle">4</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_4" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_4" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">应收利息<br></td> <td class="report_middle_middle">5</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_5" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_5" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">应收账款<br></td> <td class="report_middle_middle">6</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_6" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_6" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">其它应收款</td> <td class="report_middle_middle">7</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_7" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_7" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2"> 预付帐款<br></td> <td class="report_middle_middle">8</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_8" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_8" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2"> 应收补贴款<br></td> <td class="report_middle_middle">9</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_9" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_9" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">存货<br></td> <td class="report_middle_middle">10</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_10" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_10" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">待摊费用<br></td> <td class="report_middle_middle">11</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_11" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_11" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">一年内到期的长期债券投资<br></td> <td class="report_middle_middle">21</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_12" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_12" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">其他流动资产<br></td> <td class="report_middle_middle">24</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_13" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_13" size="15" class="reportTableInputEditRight"></td> </tr> <tr> <td class="report_blank_left2">流动资产合计<br></td> <td class="report_middle_middle">31</td> <td class="report_middle_middle"><input name="sb_zcfzb_ncs_14" onfocus="this.select()" type="text" id="sb_zcfzb_ncs_14" size="15" readonly class="reportTableInputTitleRight"></td> </tr> <input type="button" value="test" onclick="setJson()"> </form> </body> </html>
javascript公式解析计算器的简单说明和源码放在我的另外一篇博客文章里(http://huangyuanmu.iteye.com/admin/blogs/469190),有兴趣的话,可以看看。