1、前言
项目中一个考勤信息功能,考勤信息的数据表结构如下:
CREATE TABLE `t_attendance` (
`id` varchar(50) NOT NULL,
`beautician_id` varchar(50) NOT NULL COMMENT '美容师id',
`att_date` date DEFAULT NULL COMMENT '考勤日期',
`att_type` tinyint(4) DEFAULT NULL COMMENT '考勤类型:1:出勤;2:出勤半天;3:请假;4:迟到;5:旷工;6:休假;',
`late_min` int(11) DEFAULT NULL COMMENT '迟到分钟数',
`leavebill_min` int(11) DEFAULT NULL COMMENT '请假分钟数',
`summary` text COMMENT '备注',
`create_date` date DEFAULT NULL COMMENT '创建日期',
`update_date` date DEFAULT NULL COMMENT '修改日期',
`update_id` varchar(50) DEFAULT NULL COMMENT '修改id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='考勤信息'
考勤表数据如下图:
客户要求实现的界面样式如下图:
说明:根据年月查询店铺员的考勤信息,每个月份的天数是不一样的,5月份31天,6月份30天,2月份根据年份的不同,天数也不一样。所以上图的datagrid列表中的列是动态变化的。
A、该功能需求用的技术、知识点
1、MySql行转列、group_concat(此处可参考本人之前blog MySql行转列、group_concat使用)
2、js中动态创建datagrid列
3、EasyUi日期控件datebox设置,只显示年月,也只能选择年月。该问题查看本人的blogEasyUi日期控件datebox设置,只显示年月,也只能选择年月
4、EasyUi点击单元格查看、编辑员工某一天的考勤信息
2、代码实现
1、图中datagrid的列分两种,员工姓名是frozenColumns,
列,其他动态列是columns。
att.jsp页面代码片段
//获取年月日期框的年月值
var attYearMonthStr = $("#attYearMonth").datebox("getValue");
//${headerString}是获取跳转到att.jsp页面时后台丢取的列集合数据字符串
//${headerString}字符串的内容为'2017-06-01,2017-06-02 ...省略 2017-06-30'
var headerString = '${headerString}';
//将字符串转换为datagrid的column的data,然后在页面中可以直接用colObjArr
var colObjArr = covertHeader(headerString);
//创建考勤datagrid
var attDataGrid = $('#attDataGrid').datagrid({
url : '${pageContext.request.contextPath}/shop/att/queryAtts.do?attYearMonth=' +attYearMonthStr ,
fit : true,
fitColumns : false,
border : false,
idField : 'id',
remoteSort: false,
singleSelect:true,
checkOnSelect : true,
selectOnCheck : true,
nowrap : true,
showPageList:false,
frozenColumns : [ [ {
field : 'id',
title : '编号',
width : 120,
hidden : true
},{
field : 'name',
title : '员工姓名',
width : 120,
align:'center'
}
]],
//使用后台丢取的数据动态加载动态列
columns:[colObjArr],
//下面的是测试数据,(也可以理解为示例数据)
/* columns:[ [ {
field : '2017-06-01',
title : '2017-06-01',
width : 100,
align:'center',
formatter: function (value, rowData, rowIndex) {
if(value == null){
return "";
}else if(value == '出勤'){
return value;
}else{
return '<font color="red">'+value+'</font>';
}
}
},{
field : '2017-06-02',
title : '2017-06-02',
width : 100,
align:'center',
formatter: function (value, rowData, rowIndex) {
if(value == null){
return "";
}else if(value == '出勤'){
return value;
}else{
return '<font color="red">'+value+'</font>';
}
}
}]], */
toolbar : '#attToolbar',
onLoadSuccess : function() {
$(this).datagrid('clearChecked');
$(this).datagrid('clearSelections');
},
onSelect : function(rowIndex, rowData){
},
onClickRow: function (rowIndex, rowData) {
$(this).datagrid('unselectRow', rowIndex);
},
//单击单元格
onClickCell:function(rowIndex, field, value){
//根据rowIndex获取datagrid的行
var row = $('#attDataGrid').datagrid('getData').rows[rowIndex];
//通过row获取员工id
var beauticianId = row.id;
//获取列头,实际上就是员的考勤日期
var attDate = field;
//弹出考勤设置页面
showAtt(beauticianId,attDate);
}
}
});
covertHeader转换函数:
根据列数据动态生成datagrid的列data。
//动态添加列,将字符串转换为datagrid的column的data
function covertHeader(headerString){
//datagrid的columns集合
var colObjArr = new Array();
if(headerString){
var headArr = headerString.split(',');
for(var i = 0;i < headArr.length; i++) {
var fieldName = headArr[i];
//创建一个column列对象
var colObj = new Object();
//设置field属性
colObj['field'] = fieldName;
//设置title属性
colObj['title'] = fieldName;
colObj['width'] = '120';
colObj['align'] = 'center';
colObj['formatter'] = function(value,rowData,rowIndex){
if(value == null){
return "";
}else if(value == '出勤'){
return value;
}else{
return '<font color="red">'+value+'</font>';
}
};
//将创建的column列对象添加到columns集合
colObjArr.push(colObj);
}
}
return colObjArr;
}
controller跳转到att.jsp页面的代码
/**
* 跳转考勤信息页面
* @return
*/
@RequestMapping("/goToAttJsp")
public String goToAttJsp(HttpServletRequest request){
try {
//获取当前月的第一天
Date beginDate = DateUtil.getCurrentMonthFirstDay();
//获取当前月的天数
int days = DateUtil.getCurrentMonthDaysCount();
//当前月的日期集合
String[] dateArr = new String[days];
for (int i = 0; i < dateArr.length; i++) {
//当月的第一天加i
Date tempDate = DateUtil.dateAddToDate("d", i, beginDate, "yyyy-MM-dd");
//将当月的第i天添加到当月的日期集合中
dateArr[i] = DateUtil.datetoStr(tempDate, "yyyy-MM-dd");
}
//动态拼装datagrid列头信息
String headerString = StringUtil.join(dateArr, ",");
request.setAttribute("headerString", headerString);
return "/views/shop/att/att";
} catch (Exception e) {
log.error("跳转考勤信息页面失败",e);
}
return "/error/500";
}
考勤列表datagrid通过url /shop/att/queryAtts.do加载数据的代码:
controller数据:
/**
* 查询某店铺的某个月份的所有考勤信息
* @param attYearMonth 考勤年月
* @param request
* @return
*/
@ResponseBody
@RequestMapping("/queryAtts")
public List<Map<String,Object>> queryAtts(String attYearMonth){
try {
//根据动态列封装的动态数据
List<Map<String,Object>> result = new ArrayList<Map<String,Object>>();
//查询某个店铺某个月的考勤信息
List<Object[]> rows = attendanceService.queryAttendances(Constant.SHOP_ID, attYearMonth);
if(rows != null && rows.size() > 0){
for(Object[] row : rows){
//考勤id
String id = row[0].toString();
//员工姓名
String name = row[1].toString();
//员工某个月份考勤日期集合字符串
String att_dates = row[2].toString();
//员工某个月份考勤类型集合字符串
String att_types = row[3] == null ? "" : row[3].toString();
//员工某个月份迟到分钟数集合字符串
String late_mins = row[4] == null ? "" : row[4].toString();
//员工某个月份请假分钟数集合字符串
String leavebill_mins = row[5] == null ? "" : row[5].toString();
Map<String,Object> map = new HashMap<String,Object>();
map.put("id", id);
map.put("name", name);
if(StringUtil.notNull(att_dates)){
//员工某个月份考勤日期集合数组
String[] attDateArr = att_dates.split(",");
//员工某个月份考勤类型集合数组
String[] attTypeArr = att_types.split(",");
//员工某个月份迟到分钟数集合数组
String[] lateMinAtt = late_mins.split(",");
//员工某个月份请假分钟数集合数组
String[] leavebillMinAtt = leavebill_mins.split(",");
for (int i = 0; i < attDateArr.length; i++) {
if(StringUtil.notNull(attTypeArr[i])){
//考勤类型
int attType = Integer.parseInt(attTypeArr[i]);
//考勤信息
String attInfo = getAttInfo(attType);
if(attType == 3){
//请假分钟数
attInfo += " :" + leavebillMinAtt[i] + "分";
}else if(attType == 4){
//迟到分钟数
attInfo += " :" + lateMinAtt[i] + "分";
}
//设置员工某一天的考勤信息
map.put(attDateArr[i], attInfo);
}
}
}
result.add(map);
}
}
return result;
} catch (Exception e) {
log.error("查询某店铺的某个月份的所有考勤信息失败",e);
}
return null;
}
service层代码:
sql语句中使用了行转列以及group_concat
/**
*
* @Description 查询某店铺的某个月份的所有考勤信息
* @param shopId 店铺id
* @param attYearMonth 查询考勤的年月
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
@Override
public List<Object[]> queryAttendances(String shopId, String attYearMonth) throws Exception {
//月初1号
//attYearMonth = "2017-06";
Date beginDate = DateUtil.strToDate(attYearMonth + "-01", "yyyy-MM-dd");
//月末最后一天(月初1号加一个月)
Date endDate = DateUtil.getLastDayByYearMonth(attYearMonth);
StringBuffer sb = new StringBuffer(" select t.beautician_id,b.name as bname, ");
sb.append(" GROUP_CONCAT(t.att_date) as att_dates, ");
sb.append(" GROUP_CONCAT(IFNULL(t.att_type,' ')) as att_types, ");
sb.append(" GROUP_CONCAT(IFNULL(t.late_min,' ')) as late_mins, ");
sb.append(" GROUP_CONCAT(IFNULL(t.leavebill_min,' ')) as leavebill_mins, ");
sb.append(" GROUP_CONCAT(t.summary) as summarys ");
sb.append(" from t_attendance t,t_beautician b ");
sb.append(" where t.beautician_id = b.id ");
sb.append(" and t.att_date >= ? ");
sb.append(" and t.att_date <= ? ");
sb.append(" group by t.beautician_id ");
return (List<Object[]>)baseDao.queryBySql(sb.toString(), beginDate,endDate);
}
3、点查询按钮动态生成列的方式(此方式与上面的跳转到att.jsp页面生成动态列的方式不同)
/**
* 查询考勤信息
*/
function getAtts(){
var attYearMonthStr = $("#attYearMonth").datebox("getValue");
//通ajax从后台动态获取动态列的字符串
$.ajax({
type:"POST",
dataType : "json",
async: false,
url : '${pageContext.request.contextPath}/shop/att/queryHeader.do',
data : {attYearMonth:attYearMonthStr},
success : function(json){
//从后台获取的动态列的字符串
var headerStr = json.obj;
//将字符串转换为datagrid的column的data
var colObjArr = covertHeader(headerStr);
//动态加载动态列
var options={};
options.columns = [colObjArr];
$('#attDataGrid').datagrid(options);
//动态列重新加载后刷新datagrid
$('#attDataGrid').datagrid('reload');
},
error:function(){
messagerShow('提示', json);
}
});
4、EasyUi点击单元格查看、编辑员工某一天的考勤信息
下面的代码也在考勤列表(上面att.jsp页面代码片段)中
//单击单元格
onClickCell:function(rowIndex, field, value){
//根据rowIndex获取datagrid的行
var row = $('#attDataGrid').datagrid('getData').rows[rowIndex];
//通过row获取员工id
var beauticianId = row.id;
//获取列头,实际上就是员的考勤日期
var attDate = field;
//弹出考勤设置页面
showAtt(beauticianId,attDate);
}
}
5、小结:上面的代码是一个初步的实现,可以进一步优化的地方有,动态生成列的两个地方都是从后台获取数据,可以改为根据databox年月框的值,在页面前端动态生成动态列的数据。后面有时间会将前端动态生成列的代码补上。