基于JavaEE的智能人事管理系统(OA办公系统)

JSP 专栏收录该内容
5 篇文章 0 订阅

智能OA办公系统

1.前言

本套系统主要实现的是OA办公系统中一些常用发功能,还有一些功能因为时间的原因没有开发,但主线功能基本完善。前端页面模板用的是GitHub上面一位老兄OA系统办公模板,但功能上面的话我都进行了重新编写,用自己的代码方式改了过来,并添加了很多功能点。

2.准备工作

开发环境:MySQL8.0,JDK1.8,Tomcat9.0

开发工具:eclipse2020,Navicat15,HBuilder X,vscode。

开发语言:java、html、css、javascript

第三方工具库:hutool、fastjson、jstl、bootstrap、jQuery、echarts、font-awesome

3.项目结构

在这里插入图片描述
在这里插入图片描述

4.部分界面截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

由于系统的页面很多,就不一一截图了,总体的功能较为丰富,主线功能都完成。在人事管理中心的一个管理界面,对员工的一些信息进行了数据可视化分析,用到了echarts.js库,主要是把员工的学历、居住地、毕业学校、专业的数据进行了分析。

5.部分代码分析

5.1.1 ajax登录和添加员工功能

这部分实现的原理在《基于JavaEE(JSP)的共享资料平台的设计与实现》的第五点有说明,在这边就不继续介绍了。其JS代码部分基本上都是一样,唯一有差别的就是在jsp文件中,表单的格式不一样罢了。

5.1.2 考勤打卡功能

这是打卡日历图的代码,实现的功能为打卡日历图的显示,上班打卡一次,刷新一次会报红,因为没有继续打卡第二次,只有下班打卡后才会显示正常,下面环形也会显示全勤。日历图展示的时间数据是取最早打卡记录和最晚打卡记录,

数据库查询语句为SELECT EMP_ID,ATT_DATE,min(ATT_SIGNIN) as ATT_SIGNIN,max(ATT_SIGNOUT) as ATT_SIGNOUT from ATTENDANCE GROUP BY ATT_DATE,就用到了最大的时间和最小的时间。

    /**
	打卡日历模块
 */
(function(undefined) {
	var _global;
	//工具函数
	//配置合并
	function extend(def, opt, override) {
		for(var k in opt) {
			if(opt.hasOwnProperty(k) && (!def.hasOwnProperty(k) || override)) {
				def[k] = opt[k]
			}
		}
		return def;
	}
	//日期格式化
	function formartDate(y, m, d, symbol) {
		symbol = symbol || '-';
		m = (m.toString())[1] ? m : '0' + m;
		d = (d.toString())[1] ? d : '0' + d;
		return y + symbol + m + symbol + d
	}

	function Schedule(opt) {
		var def = {},
			opt = extend(def, opt, true),
			curDate = opt.date ? new Date(opt.date) : new Date(),
			year = opt.selectYear || curDate.getFullYear(),
			month = opt.selectMonth || curDate.getMonth(),
			day = curDate.getDate(),
			currentYear = curDate.getFullYear(),
			currentMonth = curDate.getMonth(),
			currentDay = curDate.getDate(),
			selectedDate = '',
			//缺勤
			qqDate = opt.qqDate || "",
			zcDate = opt.zcDate || "",
			el = document.querySelector(opt.el) || document.querySelector('body'),
			_this = this;
		var bindEvent = function() {
//			if(el.dataset['cc']){
				el.addEventListener('click', function(e) {
					switch(e.target.id) {
						case 'nextMonth':
							_this.nextMonthFun();
							break;
						case 'nextYear':
							_this.nextYearFun();
							break;
						case 'prevMonth':
							_this.prevMonthFun();
							break;
						case 'prevYear':
							_this.prevYearFun();
							break;
						default:
							break;
					};
					if(e.target.className.indexOf('currentDate') > -1) {
						opt.clickCb && opt.clickCb(year, month + 1, e.target.innerHTML,e.target);
						selectedDate = e.target.title;
						day = e.target.innerHTML;
						render();
					}
				}, false)
//				el.dataset['cc']=1;
//			}
		}
		var init = function() {
			var scheduleHd = '<div class="schedule-hd">' +
				'<div>' +
				'<span class="arrow icon iconfont icon-112leftarrowhead" id="prevMonth"></span>' +
				'</div>' +
				'<div class="today">' + year + "年" + (month + 1) + "月" + '</div>' +
				'<div>' +
				'<span class="arrow icon iconfont icon-111arrowheadright" id="nextMonth"></span>' +
				'</div>' +
				'</div>'
			var scheduleWeek = '<ul class="week-ul ul-box clearfix">' +
				'<li>日</li>' +
				'<li>一</li>' +
				'<li>二</li>' +
				'<li>三</li>' +
				'<li>四</li>' +
				'<li>五</li>' +
				'<li>六</li>' +
				'</ul>'
			var scheduleBd = '<ul class="schedule-bd ul-box clearfix" ></ul>';
			el.innerHTML = scheduleHd + scheduleWeek + scheduleBd;
			bindEvent();
			render();
		}
		var render = function() {
			var fullDay = new Date(year, month + 1, 0).getDate(), //当月总天数
				startWeek = new Date(year, month, 1).getDay(), //当月第一天是周几
				total = (fullDay + startWeek) % 7 == 0 ? (fullDay + startWeek) : fullDay + startWeek + (7 - (fullDay + startWeek) % 7), //元素总个数
				lastMonthDay = new Date(year, month, 0).getDate(), //上月最后一天
				eleTemp = [];
			for(var i = 0; i < total; i++) {
				if(i < startWeek) {
					var nowDate = formartDate(year, month, ((lastMonthDay - startWeek) + 1 + i), '-');
					var addClass = '';
					
					eleTemp.push('<li class="other-month"><span class="dayStyle ' + addClass + '">' + (lastMonthDay - startWeek + 1 + i) + '</span></li>')
				} else if(i < (startWeek + fullDay)) {
					var nowDate = formartDate(year, month + 1, (i + 1 - startWeek), '-');
					var addClass = '';
					var attSignin = '';
					var attSignout = '';
					//					selectedDate == nowDate && (addClass = 'selected-style');
					for(var j = 0; j < zcDate.length; j++) {
						zcDate[j].attDate == nowDate && (addClass = 'zc_day', attSignin = zcDate[j].attSignin, attSignout = zcDate[j].attSignout);
					}
					for(var z = 0; z < qqDate.length; z++) {
						qqDate[z].attDate == nowDate && (addClass = 'qq-style', attSignin = qqDate[z].attSignin, attSignout = qqDate[z].attSignout);
					}
					//					formartDate(currentYear,currentMonth+1,currentDay,'-') == nowDate && (addClass = 'today-flag');
					eleTemp.push('<li class="current-month" ><span  class="currentDate dayStyle ' + addClass + '">' + (i + 1 - startWeek) + '</span><div class="day_time"><div>上班:' + attSignin + '</div><div>下班:' + attSignout + '</div></li>')
				} else {
					eleTemp.push('<li class="other-month"><span class="dayStyle">' + (i + 1 - (startWeek + fullDay)) + '</span></li>')
				}
			}
			el.querySelector('.schedule-bd').innerHTML = eleTemp.join('');
			el.querySelector('.today').innerHTML = year + "年" + (month + 1) + "月";
		};
		this.nextMonthFun = function() {
				if(month + 1 > 11) {
					year += 1;
					month = 0;
				} else {
					month += 1;
				}
				render();
				opt.nextMonthCb && opt.nextMonthCb(year, month + 1, day);
			},
			this.nextYearFun = function() {
				year += 1;
				render();
				opt.nextYeayCb && opt.nextYeayCb(year, month + 1, day);
			},
			this.prevMonthFun = function() {
				if(month - 1 < 0) {
					year -= 1;
					month = 11;
				} else {
					month -= 1;
				}
				render();
				opt.prevMonthCb && opt.prevMonthCb(year, month + 1, day);
			},
			this.prevYearFun = function() {
				year -= 1;
				render();
				opt.prevYearCb && opt.prevYearCb(year, month + 1, day);
			}
		init();
	}
	//将插件暴露给全局对象
	_global = (function() {
		return this || (0, eval)('this')
	}());
	if(typeof module !== 'undefined' && module.exports) {
		module.exports = Schedule;
	} else if(typeof define === "function" && define.amd) {
		define(function() {
			return Schedule;
		})
	} else {
		!('Schedule' in _global) && (_global.Schedule = Schedule);
	}

}());

5.1.3 ajax与Bootstrap Table实现表格内容的读写与分页

这里的列表代码以部门管理为例进行演示。

这是前端table的写法,主要是把表头给写出来,然后利用bootstrap的写法,在js里面写实现方法,还是比较方便的。下面就来一一讲解实现过程。

<table id="datagrid" class="table table-bordered table-striped table-hover">
    <thead>
        <tr>
            <th data-width="60" data-align="center"
                data-formatter="indexFormatter">#</th>
            <th data-field="deptId" data-align="center">部门编号</th>
            <th data-field="deptName" data-align="center">部门名称</th>
            <th data-field="deptUserid" data-align="center">负责人</th>
            <th data-field="deptCreatetime" data-align="center" data-formatter="dateFormatter">创建时间</th>
            <th data-field="deptId" data-class="p-1" data-width="150"
                data-align="center" data-formatter="optionFormatter">操作</th>
        </tr>
    </thead>
</table>
CLICK ME

```java

然后在其他<th></th>标签中,有一个data-field属性,这里表达的是这一列所需要的展示的值,也就是从数据库返回的值显示的内容。

在创建时间的<th></th>的标签里面,写了一个data-formatter="dateFormatter",和上面的原理一样,在下面的js代码找到dateFormatter函数。主要是对数据库传来的时间进行格式化展示。

/**
	装载下拉框的角色列表
 */
var searchDeptForm = $(document.forms.searchDeptForm);
var searchDeptForms = document.forms.searchDeptForm;

//表单提交事件
searchDeptForms.onsubmit = ()=>{
	$.post(
		searchDeptForms.action,
		sys.form.param(searchDeptForms).toString(),
		function(data){
			if(data.code==200){
				//sys.js库中定义的方法,可以弹出提示界面
				sys.toastr.success("查询成功");
			}else{
				sys.toastr.error(data.message);
			}
		},"json"
	);
	return false;
}

// 获取部门下拉框的数据
var deptIdSelect = $(document.forms.searchDeptForm.deptIdSelect);
$.get(
	"department.let?action=listDepts",
	function(data){
		for(let dept of data) {
			deptIdSelect.append(`<option value="${dept.deptId}">${dept.deptName}</option>`);
		}
	},"json"
);


//保存查询条件
var searchParams = new URLSearchParams();
searchDeptForm.on("submit",function(){
	searchParams = sys.form.param(searchDeptForm[0]);
	datagrid.bootstrapTable("refresh",{pageNumber:1});
	return false;
});

/**
	表格内容填充方式,从数据库请求的数据,填充到表格中
*/
var datagrid = $("#datagrid").bootstrapTable({
	url: "department.let?action=page",
	dataField: "list",//rows
	totalField: "total",
	queryParamsType: "",//limit
	pagination: true,
	sidePagination: "server",//client
	queryParams:function(params) { 
	  for(let name of searchParams.keys()){//添加搜索条件
		  params[name]=searchParams.get(name);
	  }
	  return params 
    }
});

/**
	列表最前面加索引
 */
var indexFormatter = function(value, row, index, fieldName) {
	return index + 1;
}

/**
	给时间设置0
 */
function addZero(n) {
	return n < 10 ? '0' + n : '' + n;
};

/**
	格式化时间
 */
var dateFormatter = function(value, row, index, fieldName) {
	var date = new Date(value);
	var time = date.getFullYear() + "-" + addZero(date.getMonth() + 1) + "-" + addZero(date.getDate());
	return time;
}

/**
 * 格式化表格操作菜单
 */
var optionFormatter = function(value, row, index) {
	return `<div class="dropdown">
  <button class="btn btn-outline-primary btn-block dropdown-toggle" type="button" data-toggle="dropdown">
    操作
  </button>
  <div class="dropdown-menu dropdown-menu-right">
    <a class="dropdown-item"   href="department.let?action=getDeptInfo&deptId=${value}">查看&修改</a>
    <a class="dropdown-item _delete" data-index="${index}" href="javascript:void(0);">删除</a>
  </div>
</div>`;
}

/**
	操作按钮
 */
datagrid.on("click", "._delete", function() {//删除
	let obj = $(this);
	let index = obj.data("index");//data-index
	let row = datagrid.bootstrapTable("getData")[index];
	sys.confirm(`您确定要删除[${row.deptName}]吗?`, function(r) {
		if (r) {
			$.post(
				"department.let?action=delete",
				{ "deptId": row.deptId },
				function(data) {
					if (data.code == 200) {
						sys.toastr.success(`删除用户[${row.deptName}]成功`);
						datagrid.bootstrapTable("refresh");
					} else {
						sys.toastr.error(data.message);
					}
				}, "json"
			);
		}
	});
});

5.1.4 员工各类信息统计Echarts代码

环状比例图的实现代码,主要用的是echarts库。传入的数据有三种TextData,DigitalData,titleText,分别为图例数据、员工详情数据、该图形的标题数据。

function EmpCityChart(TextData,DigitalData,titleText) {
    var myChart = echarts.init(document.getElementById('empCity'));
    var img = 'data:image/png;base64,iVBORw0K....VORK5CYII=';
    var trafficWay = DigitalData;
    var data = [];
    var color=['#00ffff','#00cfff','#006ced','#ffe000','#ffa800','#ff5b00','#ff3000']
    for (var i = 0; i < trafficWay.length; i++) {
        data.push({
            value: trafficWay[i].value,
            name: trafficWay[i].name,
            itemStyle: {
                normal: {
                    borderWidth: 5,
                    shadowBlur: 20,
                    borderColor:color[i],
                    shadowColor: color[i]
                }
            }
        }, {
            value: 2,
            name: '',
            itemStyle: {
                normal: {
                    label: {
                        show: false
                    },
                    labelLine: {
                        show: false
                    },
                    color: 'rgba(0, 0, 0, 0)',
                    borderColor: 'rgba(0, 0, 0, 0)',
                    borderWidth: 0
                }
            }
        });
    }
    var seriesOption = [{
        name: '',
        type: 'pie',
        clockWise: false,
        radius: [105, 109],
        hoverAnimation: false,
        itemStyle: {
            normal: {
                label: {
                    show: true,
                    position: 'outside',
                    color: '#ddd',
                    formatter: function(params) {
                        var percent = 0;
                        var total = 0;
                        for (var i = 0; i < trafficWay.length; i++) {
                            total += trafficWay[i].value;
                        }
                        percent = ((params.value / total) * 100).toFixed(0);
                        if(params.name !== '') {
                            return titleText+':' + params.name + '\n' + '\n' + '占百分比:' + percent + '%';
                        }else {
                            return '';
                        }
                    },
                },
                labelLine: {
                    length:30,
                    length2:100,
                    show: true,
                    color:'#00ffff'
                }
            }
        },
        data: data
    }];
    option = {
        backgroundColor: '#5e7c85',
        color : color,
        title: {
            text:titleText,
            top: '48%',
            textAlign: "center",
            left: "49%",
            textStyle: {
                color: '#fff',
                fontSize: 22,
                fontWeight: '400'
            }
        },
        graphic: {
            elements: [{
                type: "image",
                z: 3,
                style: {
                    image: img,
                    width: 178,
                    height: 178
                },
                left: 'center',
                top:  'center',
                position: [100, 100]
            }]
        },
        tooltip: {
            show: false
        },
        legend: {
            icon: "circle",
            orient: 'horizontal',
            x: 'center',
            data:TextData,
            top: 10,
            align: 'left',
            textStyle: {
                color: "#fff"
            },
            itemGap: 20
        },
        toolbox: {
            show: false
        },
        series: seriesOption
    }
    myChart.setOption(option);
}

ajax请求数据,这里请求的数据是员工的岗位数据分析数据,将获得的数据进行格式的一些转换,然后调用上面的函数,就可以正常显示图形了。

function empDegree(){
	$.get(
		"chartData.let?action=getEmpDegreeData",
		function(data){
			var empText=[];
			var empData=[];
			for(let i=0;i<data.data.length;i++){
				empText.push(data.data[i].empTiptopdegree);
				empData.push({name:data.data[i].empTiptopdegree,value:data.data[i].empData*100});
			}
			EmpCityChart(empText,empData,"最高学历")
		},"json"
	);
}

servlet实现获取数据。这里写了SQL语句是因为在service和dao包中的实现类用的是同一个方法,只需要传入不同的SQL语句和异常代号和异常信息就可以了。

private ChartDataService chartDataService = new ChartDataServiceImpl();

/**
* -获取员工的学历数据
* @return
*/
public R<?> getEmpDegreeData(){
    String sql = "select EMP_TIPTOPDEGREE,COUNT(EMP_TIPTOPDEGREE) as EMP_DATA from EMPLOYEE GROUP BY EMP_TIPTOPDEGREE";
    List<Employee> empData = chartDataService.getEmpData(sql,1001,"获取员工学历数据失败");
    return R.ok(empData);
}

ChartDataDAO.java实现

/**
* -由于代码非常相似,所以只需要根据SQL语句不同查询不同的字段就行,这里查询的是员工的数据
* @return
* @throws SQLException 
*/
public List<Employee> getEmpData(String sql) throws SQLException {
    List<Object> params = new ArrayList<Object>();
    return DBUtil.list(sql, Employee.class, params.toArray());
}

6.总结

以上的系统主线功能基本完成,从GitHub大佬用的模板改进了全部功能,现在找不到这个GitHub的地址是什么了,如果有侵权请联系。用来学习的话,能够把全部代码总一遍,基本上可以学会所有的javaee知识,如果JavaScript底子好的话,还能够深入的研究一下ajax代码。ajax代码比传统MVC好用多了。

好了,这次的项目分享到此也差不多了。觉得小弟写的不错的话,可以点赞加关注一下,谢谢!有需要源码的小伙伴也可以搜索企鹅号863772270,编码不易,请作者喝瓶水即可。

DataDAO.java实现

/**
* -由于代码非常相似,所以只需要根据SQL语句不同查询不同的字段就行,这里查询的是员工的数据
* @return
* @throws SQLException 
*/
public List<Employee> getEmpData(String sql) throws SQLException {
    List<Object> params = new ArrayList<Object>();
    return DBUtil.list(sql, Employee.class, params.toArray());
}

6.总结

以上的系统主线功能基本完成,从GitHub大佬用的模板改进了全部功能,现在找不到这个GitHub的地址是什么了,如果有侵权请联系。用来学习的话,能够把全部代码总一遍,基本上可以学会所有的javaee知识,如果JavaScript底子好的话,还能够深入的研究一下ajax代码。ajax代码比传统MVC好用多了。

好了,这次的项目分享到此也差不多了。觉得小弟写的不错的话,可以点赞加关注一下,谢谢!有需要源码的小伙伴也可以搜索企鹅号863772270,编码不易,请作者喝瓶水即可。

  • 2
    点赞
  • 0
    评论
  • 17
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
一、开发此系统的目的: 利用业余时间开发了此系统,主要用于解决中小企业的人事管理问题,简化其手工部分,实现传统公司的互联网化。本次属于二次开发,版权归原作者:数通畅联。请在免费开源、非商业应用的前提下进行使用。 二、系统实现的功能: 1, 基础功能:登录、员工信息维护、考勤管理、加班管理、请假管理、薪资管理 2,高级功能:员工信心核准、考勤导出、加班核准、请假核准、薪资汇总等,支持各个维度数据的excel导出或pdf导出 3,系统功能:修改密码、组织结构管理(部门管理)、角色管理、权限管理(功能管理)、编码类型及值、系统日志、附件上传下载等 三、系统的角色说明: 1,admin :此用户能管理员工信息、能管理组织结构、权限、角色、查看日志、管理编码、附件管理等 2,普通用 :能查看/编辑自己的信息,能考勤,查看所有人考勤,能申请加班/请假,能查看自己的薪资 3,人事负责人:具有普通用户的全部权限,另外,能添加员工、核准员工信息 4, 业务负责人 :具有人事负责人的所有权限, 此外,能批准加班,能批准请假 5,薪资负责人 :具有人事负责人的所有权限,能汇总薪资,编辑员工薪资 四、项目开发环境 此项目基于eclipse + tomcat8.0.38 + mysql开发,开发、运行环境比较宽松。也可以用idea。 可以通过下载我们的release版本, 关于工程导入eclipse: 首先clone代码, 导入工程到eclipse: File->Import->Exsisting project into workspace 导入后,应该会有报错, 右键工程,Build path -> Configure Build path ,通过add Library -> add servertime 将你的tomcat lib加进来(一般在eclipse中添加tomcat后,就会有Apache Tomcat V8.0), 然后就确定,就OK了 五,项目部署 1, 创建数据库 CREATE DATABASE IF NOT EXISTS aeaihr DEFAULT CHARSET utf8 COLLATE utf8_general_ci; 2, 将aeaihr_mysql.sql导入到数据库中 3, 将hr.war放到tomcat目录/webapps/ 下, 重启tomcat
©️2022 CSDN 皮肤主题:像素格子 设计师:CSDN官方博客 返回首页

打赏作者

少年码农历险记

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值