一、需求描述
A项指标 | B项指标 | |
---|---|---|
测试结果1 | 111 | 222 |
测试结果2 | 333 | 444 |
说明:
如果开始填写了000,并且已经保存了(没有保存前过程中修改不用留痕)。再修改成111,那么这个单元格里,111那里需能够有个标识提示(可以是字体变颜色、背景变色、旁边 有个什么标记等。),然后点击那里,可以查看到修改前后的信息,比如:
修改后:111,修改前:000,修改时间:xxxxxxx
二、需求分析
三、设计过程
1.创建数据表
DEMO_DEPT_BUDGET表
CREATE TABLE DEMO_DEPT_BUDGET (
DEPTID CHAR(10),
TRAVELBUDGET DECIMAL(10,2),
SALARYBUDGET DECIMAL(10,2),
ALLOWANCEBUDGET DECIMAL(10,2)
) ;
DEMO_DEPT_BUDGET_LOG表
CREATE TABLE DEMO_DEPT_BUDGET_LOG (
DEPTID CHAR(10),
BUDGETTYPE VARCHAR(20),
OLD_VALUE DECIMAL(10,2),
NEW_VALUE DECIMAL(10,2),
USERID VARCHAR(20),
ALTERDATE DATE
) ;
DEPT表
CREATE TABLE DEPT (
DEPTID CHAR(10),
DEPTNAME CHAR(30),
) ;
2.设计皕杰报表填报报表
新建参数
dept(字符串类型):选择显示的部门
新建数据集
dept
select deptid,deptname from dept
dept_budget
="select b.DEPTID,d.DEPTNAME,b.TRAVELBUDGET,b.SALARYBUDGET,b.ALLOWANCEBUDGET from demo_dept_budget b left join dept d on b.deptid=d.deptid where 1=1"+if(@dept=null,""," and b.deptid='"+@dept+"'")
dept_budget_log
SELECT l.DEPTID,d.DEPTNAME,l.BUDGETTYPE,l.OLD_VALUE,l.NEW_VALUE,l.ALTERDATE,l.USERID FROM DEMO_DEPT_BUDGET_LOG l LEFT JOIN DEPT d ON l.DEPTID=d.DEPTID
报表编辑区
填报设置
查询表单
3.编写填报监听自定义类
根据帮助文档-开发指南-javadoc中提供的接口(bios.report.api.events.IFillinEventListener)写自定义填报监听事件
实例代码:
package bios.report.dev.examples.event;
import java.sql.*;
import java.util.*;
import com.jfinal.plugin.activerecord.*;
import bios.report.api.events.IFillinEventListener;
import bios.report.api.usermodel.*;
public class DeptBudgetEventListener implements IFillinEventListener {
@Override
public String onCommitData(ReportMark arg0) {
return null;
}
@Override
public void onCommitDataFinished(ReportMark arg0) {
}
@Override
public String onUpdateData(ReportMark mark, FillinDatas data) {
return null;
}
@Override
// 填报完成后,执行将修改记录保存到日志表
public void onUpdateDataFinished(ReportMark mark, FillinDatas data) {
// 获取登录用户的ID
String userid = getUserId();
// 获取填报操作信息
List<FillinDataRow> list = data.getDatas();
for (int i = 0; i < list.size(); i++) {
FillinDataRow row = list.get(i);
valueCompare(row, userid);
}
}
// 比较数据里的修改记录,获取旧数据
private void valueCompare(FillinDataRow row, String userid) {
int deptid = Integer.parseInt(row.getDataByField("DEPTID").toString());
Connection con = getConn();
PreparedStatement ps = null;
ResultSet rs = null;
// 根据填报操作里的主键idDEPTID获取DEMO_DEPT_BUDGET表中历史记录
String sql = "SELECT b.TRAVELBUDGET,b.SALARYBUDGET,b.ALLOWANCEBUDGET FROM DEMO_DEPT_BUDGET b WHERE DEPTID=?";
double old_TRAVELBUDGET = 0;
double old_SALARYBUDGET = 0;
double old_ALLOWANCEBUDGET = 0;
try {
ps = con.prepareStatement(sql);
ps.setInt(1, deptid);
rs = ps.executeQuery();
while (rs.next()) {
old_TRAVELBUDGET = rs.getDouble(1);
old_SALARYBUDGET = rs.getDouble(2);
old_ALLOWANCEBUDGET = rs.getDouble(3);
}
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
double new_TRAVELBUDGET = (Double) row.getDataByField("TRAVELBUDGET");
double new_SALARYBUDGET = (Double) row.getDataByField("SALARYBUDGET");
double new_ALLOWANCEBUDGET = (Double) row.getDataByField("ALLOWANCEBUDGET");
// 判断新的填报操作 信息中某字段是否已修改
if (new_TRAVELBUDGET == old_TRAVELBUDGET) {
} else {
fillData(new_TRAVELBUDGET, old_TRAVELBUDGET, deptid, userid, "E4");
}
if (new_SALARYBUDGET == old_SALARYBUDGET) {
} else {
fillData(new_SALARYBUDGET, old_SALARYBUDGET, deptid, userid, "C4");
}
if (new_ALLOWANCEBUDGET == old_ALLOWANCEBUDGET) {
} else {
fillData(new_ALLOWANCEBUDGET, old_ALLOWANCEBUDGET, deptid, userid, "D4");
}
}
// 将修改记录保存到日志表
private void fillData(double new_value, double old_value, int typeid, String userid, String cell) {
Connection con = getConn();
PreparedStatement ps = null;
String sql = "insert into DEMO_DEPT_BUDGET_LOG (budgettype,deptid,userid,new_value,old_value,alterdate) values(?,?,?,?,?,CURRENT_TIMESTAMP())";
try {
ps = con.prepareStatement(sql);
ps.setString(1, cell);
ps.setInt(2, typeid);
ps.setString(3, userid);
ps.setDouble(4, new_value);
ps.setDouble(5, old_value);
ps.executeUpdate();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取登录用户ID
private String getUserId() {
String userid = "";
return userid;
}
// 获取应用数据源connection连接
private Connection getConn() {
Config sysConfig = DbKit.getConfig("sys");
Connection conn = sysConfig.getThreadLocalConnection();
if (conn == null) {
try {
conn = sysConfig.getConnection();
conn.setAutoCommit(true);
return conn;
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
}
4.填报设置中配置填报监听
打开填报设置,点击动作按钮
设置新的动作按钮,此操作,重置新的保存按钮 。
5.配置单元格背景变色
C4单元格-单元格属性-背景颜色 ,表达式: =if(dept_budget_log.count(deptid=A4 and BUDGETTYPE=‘C4’)>0,‘204,255,204’,‘255,255,255’)。这个表达式意思是:判断根据deptid和BUDGETTYPE的值判断dept_budget_log表中是否有值。如果是,就变色;如果不是,还是默认颜色。
同样,D4和E4分别设置=if(dept_budget_log.count(deptid=A4 and BUDGETTYPE=‘D4’)>0,‘204,255,204’,‘255,255,255’)、=if(dept_budget_log.count(deptid=A4 and BUDGETTYPE=‘E4’)>0,‘204,255,204’,‘255,255,255’)
6.新建弹出层
点击报表属性-WEB资源引用
在web资源引用中,添加
<div id="popupdiv"
style="display:none;background-color:#FFFFFF;min-height:80px;z-index:1001;border-radius: 3px;box-shadow:0 3px 10px 0 rgba(0,0,0,0.26), 0 0 3px 0 rgba(0,0,0,0.18);">弹出层实例</div>
7.弹出层相关js控制
在report_res文件夹下新建demo_popupdiv.js
// 显示层popupdiv
function showdiv(budgetlog,deptid,cell) {
var popupdiv = document.getElementById('popupdiv'); // 将要弹出的层
popupdiv.style.display = "block"; // popupdiv初始状态是不可见的,设置可为可见
// window.event代表事件状态,如事件发生的元素,键盘状态,鼠标位置和鼠标按钮状.
// clientX是鼠标指针位置相对于窗口客户区域的 x 坐标,其中客户区域不包括窗口自身的控件和滚动条。
popupdiv.style.left = (event.clientX - 50)+"px"; // 鼠标目前在X轴上的位置,加10是为了向右边移动10个px方便看到内容
popupdiv.style.top = (event.clientY +10)+"px";
popupdiv.style.position = "absolute"; // 必须指定这个属性,否则popupdiv层无法跟着鼠标动
gettable(budgetlog,deptid,cell)
}
// 关闭层popupdiv
function closediv() {
var popupdiv = document.getElementById('popupdiv');
popupdiv.style.display = "none";
}
//根据相关条件获取json中的符合条件的数据,然后把json中的数据拼成table然后传递给弹出层div
function gettable(budgetlog,deptid,cell){
var log1=budgetlog.result;
var log2=log1.filter((l)=>{
return l.DEPTID==deptid;
});
var log3=log2.filter((l)=>{
return l.BUDGETTYPE==cell;
});
var tableStr="<div style='text-align:center;margin-top:10px;font-size:12pt;'>修改痕迹</div><table style='margin:5px 10px 10px;min-height:30px;font-family:Microsoft Yahei;font-size:10pt;color:#333333; border:1px solid #CCCCCC;border-collapse: collapse' border='1' cellspacing='0' cellpadding='3px'>";
tableStr=tableStr+"<thead><td>部门名称</td><td>修改前数据</td><td>修改后数据</td>"
//+"<td>修改用户ID</td>"
+"<td>修改时间</td></thead>";
for(var i=0;i<log3.length;i++){
var log=log3[i];
tableStr=tableStr+"<tr><td>"
+log.DEPTNAME+"</td><td>"+log.OLD_VALUE+"</td><td>"
+log.NEW_VALUE+"</td><td>"
//+log.USERID+"</td><td>"
+log.ALTERDATE+"</td></tr>";
}
tableStr = tableStr + "</table>";
var popupdiv = document.getElementById('popupdiv');
popupdiv.innerHTML=tableStr;
}
8.报表引用popupdiv.js
打开web资源引用,引用这个js
<script type="text/javascript" src="report_res/demo_popupdiv.js"></script>
<script type="text/javascript">
function get(){}
</script>
9.单元格引用弹出层事件
C3单元格属性-WEB事件和属性设置
事件1:onmousemove,响应操作:=if(dept_budget_log.count(deptid=A4 and BUDGETTYPE=‘C4’)>0,“showdiv(”+tojson(dept_budget_log)+","+A4+",‘C4’)",“get()”)。这个表达式意思是:判断根据deptid和BUDGETTYPE的值判断dept_budget_log表中是否有值。如果是,就鼠标移动上去时,就弹出层;如果不是,执行空方法。
事件2:onmouseout,响应操作:=if(dept_budget_log.count(deptid=A4 and BUDGETTYPE=‘C4’)>0,“closediv()”,“get()”)。这个表达式意思是:判断根据deptid和BUDGETTYPE的值判断dept_budget_log表中是否有值。如果是,就鼠标移动移开时,就关闭层;如果不是,执行空方法。
同样,D4和E4也都是两个事件=if(dept_budget_log.count(deptid=A4 and BUDGETTYPE=‘D4’)>0,“showdiv(”+tojson(dept_budget_log)+","+A4+",‘D4’)",“get()”)、=if(dept_budget_log.count(deptid=A4 and BUDGETTYPE=‘D4’)>0,“closediv()”,“get()”)和=if(dept_budget_log.count(deptid=A4 and BUDGETTYPE=‘E4’)>0,“showdiv(”+tojson(dept_budget_log)+","+A4+",‘E4’)",“get()”)、=if(dept_budget_log.count(deptid=A4 and BUDGETTYPE=‘E4’)>0,“closediv()”,“get()”)
10.然后将报表集成到web应用上,预览报表。
访问报表的时候 url后跟&forwardurl=javascript:location.reload(),意思是:填报保存后,刷新页面。
http://localhost:8080/iface/report/param_query.jsp?rpt=Demo/demo_dept_budget.brt&forwardurl=javascript:location.reload()
如上图所示:市场部没有数据时,不变色
如上图所示:综合部已填入数据,背景变色 及弹出修改痕迹层。