智能OA办公系统

文章目录

  • 智能OA办公系统
    • 1.前言
    • 2.准备工作
    • 3.项目结构
    • 4.部分界面截图
    • 5.部分代码分析
      • 5.1.1 ajax登录和添加员工功能
      • 5.1.2 考勤打卡功能
      • 5.1.3 ajax与Bootstrap Table实现表格内容的读写与分页
      • 5.1.4 员工各类信息统计Echarts代码
    • 6.总结
    • 6.总结

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",//rowstotalField: "total",queryParamsType: "",//limitpagination: true,sidePagination: "server",//clientqueryParams: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-indexlet 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,编码不易,请作者喝瓶水即可。

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

  1. 基于Java毕业设计智能停车场管理系统源码+系统+mysql+lw文档+

    基于Java毕业设计智能停车场管理系统源码+系统+mysql+lw文档+ 基于Java毕业设计智能停车场管理系统源码+系统+mysql+lw文档+部署软件 本源码技术栈: 项目架构:B/S架构 开发语 ...

  2. 项目视频讲解_基于Activiti5工作流实战企业协同OA办公系统教程

    百度网盘地址:http://pan.baidu.com/s/11TiP5 分享一套Adam老师的教程,名为<基于Activiti5工作流实战企业协同OA办公系统(spring-data-jpa. ...

  3. Activiti工作流视频教程-基于Activiti5工作流实战企业协同OA办公系统

    Activiti工作流视频教程-基于Activiti5工作流实战企业协同OA办公系统(spring-data-jpa.uur前台组件) 一.Activiti工作流视频教程课程内容简介 在工作流方面,使 ...

  4. 基于Activiti5工作流实战企业协同OA办公系统(spring-data-jpa、uur前台组件)

    课程讲师:Adam 课程分类:Java 适合人群:中级 课时数量:51课时 更新程度:完毕 用到技术:Activiti.Spring-data-jpa.uur 涉及项目:协同OA办公系统 链接: ht ...

  5. 基于Go语言GoFrame+Layui的OA办公系统

    项目介绍 一款 Go 语言基于GoFrame.Layui.MySQL等框架精心打造的一款模块化.高性能.企业级的敏捷开发框架,本着简化开发.提升开发效率的初衷触发,框架自研了一套个性化的组件,实现了可 ...

  6. 基于Go语言Gin+Xorm的OA办公系统

    项目介绍 一款 Go 语言基于Gin.Xorm.Layui.MySQL等框架精心打造的一款模块化.高性能.企业级的敏捷开发框架,本着简化开发.提升开发效率的初衷触发,框架自研了一套个性化的组件,实现了 ...

  7. 基于Go语言Iris+Layui的OA办公系统

    项目介绍 一款 Go 语言基于Iris.Layui.MySQL等框架精心打造的一款模块化.高性能.企业级的敏捷开发框架,本着简化开发.提升开发效率的初衷触发,框架自研了一套个性化的组件,实现了可插拔的 ...

  8. 基于Go语言Revel+Layui的OA办公系统

    项目介绍 一款 Go 语言基于Revel.Layui.MySQL等框架精心打造的一款模块化.插件化.高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发.提升开发效率 ...

  9. 基于Go语言Beego+Layui的OA办公系统

    项目介绍 一款 Go 语言基于Beego.Layui.MySQL等框架精心打造的一款模块化.高性能.企业级的敏捷开发框架,本着简化开发.提升开发效率的初衷触发,框架自研了一套个性化的组件,实现了可插拔 ...

最新文章

  1. wds和dhcp分开做需要注意问题
  2. pandas中DataFrame的apply()方法和applymap()方法,以及python内置函数map()
  3. java设计模式---合成模式
  4. 用存储过程生成记录编号
  5. Android官方开发文档Training系列课程中文版:分享文件之分享一个文件
  6. 拖动精灵的三种方法比较
  7. 创业,如果条件允许,你最想开一个什么店?
  8. C语言,产生一组数字,并将其写入txt文档中
  9. win11玩游戏怎么样 windows11玩游戏的具体性能介绍
  10. linux基本命令示例_Linux mv命令用法和示例
  11. 软件加入使用时间_2020年,加入“midi音乐制作讲堂”内部会员,学音乐制作变得更简单...
  12. java飞机大战boos代码_飞机大战 java 源代码
  13. NOIP2016普及组T2(回文日期)题解
  14. GNN-图卷积模型-2017:GAT【消息传递(前向传播):聚合函数+更新函数】【聚合函数:attention(邻域所有节点根据注意力机制进行加权)】【训练更新函数的参数】【直推式归纳式】【同质图】
  15. php7 memcached sasl,启用MemCached的SASL认证
  16. SpringCloud项目搭建(六) —elastic-job的使用,以及consul的配置使用(衔接上篇)
  17. 多年编码经验血泪史总结,你若想学Python,必须看完这几点再做决定
  18. 联想服务器ghost系统进不去系统,联想电脑台式机开机后一直在这个界面进不了系统是为什么。...
  19. 大数据Hadoop3.1.3 HDFS 详细入门笔记
  20. 【树莓派】关于树莓派2代,更新最新内核后,DS18B20温度传感器无法找到对应文件的问题的解决

热门文章

  1. iic总线驱动(适配器驱动)详解
  2. vue3.0引入字体样式ttf文件
  3. 横岗无线充android,3线圈无线充电方案
  4. python百度语音实时识别成文字(Key值获取)
  5. 猿创征文|Java中的IO流大家族 (两万字详解)
  6. [RK3399][Android7.1] 调试笔记 --- 闪电浏览器全屏播放视频时黑屏
  7. IE浏览器的版本怎么就降下来
  8. 武汉地图json文件_echarts各省市地图js和json文件
  9. 计算机组成与系统结构输入输出控制实验,计算机组成与系统结构实验讲稿.ppt...
  10. 命令行调节linux系统声音