当前位置:网站首页>会议OA之我的审批
会议OA之我的审批
2022-07-27 04:38:00 【好爱吃香菜TvT】
目录
上次与大家分享了会议排座以及会议送审,按照项目流程来,今天与大家分享会议审批。
会议审批包含了会议查询和审批签字两个功能。
会议查询:在我的审批界面,当前用户点击查询,显示的是他还未进行审批的会议数据
审批签字:当审批人浏览完该会议内容后,可以选择驳回或者通过该会议,如果通过该会议则进行签字,驳回则不需要签字。审批签字运用到了在线绘画工具的一个插件以及签字截图功能,类似于ps美化签字图片。在后端运用到了批处理方法,同时处理将被审批的会议新增入库以及修改会议状态的事务,业务处理结果必须保持一致。
一、会议查询
实现思路:由当前登录账号作为审批人字段值,点击查询,显示该账号下还未审批的会议数据
后端:
1.Dao层方法
sql语句2和3分别是查询审批人和查询会议状态的语句
public List<Map<String, Object>> myAudit(MeetingInfo info, PageBean pageBean) throws Exception, Exception, Exception {
String sql = getSQL();
//会议标题查询
String title = info.getTitle();
if(StringUtils.isNotBlank(title)) {
sql += " and title like '%"+title+"%'";
}
//当前登陆账号是会议信息表中的审批人字段值
sql += " and a.auditor = " + info.getAuditor();
//只查询会议状态为2 的 待审核的会议
sql += " and a.state = 2 ";
//排序按照降序展示
sql += " order by a.id desc ";
return super.executeQuery(sql, pageBean);
}2、Web层
//我的审批
public String myAudit(HttpServletRequest req, HttpServletResponse resp) {
try {
PageBean pageBean = new PageBean();
pageBean.setRequest(req);
List<Map<String, Object>> infos = infoDao.myAudit(info, pageBean);
ResponseUtil.writeJson(resp, R.ok(0, "会议信息查询成功" , pageBean.getTotal(), infos));
} catch (Exception e) {
e.printStackTrace();
try {
ResponseUtil.writeJson(resp, R.error(0, "会议信息查询失败"));
} catch (Exception e1) {
e1.printStackTrace();
}
}
return null;
}前端:
1、Jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="/common/header.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="${pageContext.request.contextPath }/static/js/meeting/myAudit.js"></script>
</head>
<style>
body{
margin:15px;
}
.layui-table-cell {height: inherit;}
.layui-layer-page .layui-layer-content { overflow: visible !important;}
</style>
<body>
<!-- 搜索栏 -->
<div class="layui-form-item" style="margin:15px 0px;">
<div class="layui-inline">
<label class="layui-form-label">会议标题</label>
<div class="layui-input-inline">
<input type="hidden" id="auditor" value="${user.id }"/>
<input type="text" id="title" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-inline">
<button id="btn_search" type="button" class="layui-btn"><i class="layui-icon layui-icon-search"></i> 查询</button>
</div>
</div>
<!-- 数据表格 -->
<table id="tb" lay-filter="tb" class="layui-table" style="margin-top:-15px"></table>
<script type="text/html" id="tbar">
<a class="layui-btn layui-btn-xs" lay-event="edit">审批</a>
</script>
</body>
</html>
2、Js代码
let layer,table,$,form;
var row;
layui.use(['layer','table','jquery','form'],function(){
layer=layui.layer,
table=layui.table,
form=layui.form,
$=layui.jquery;
initTable();
//查询事件
$('#btn_search').click(function(){
query();
});
});
//初始化数据表格(我的审批)
function initTable(){
table.render({ //执行渲染
elem: '#tb', //指定原始表格元素选择器(推荐id选择器)
height: 400, //自定义高度
loading: false, //是否显示加载条(默认 true)
cols: [[ //设置表头
{field: 'id', title: '会议编号', width: 90},
{field: 'title', title: '会议标题', width: 120},
{field: 'location', title: '会议地点', width: 140},
{field: 'startTime', title: '开始时间', width: 120},
{field: 'endTime', title: '结束时间', width: 120},
{field: 'meetingState', title: '会议状态', width: 120},
{field: 'seatPic', title: '会议排座', width: 120,
templet: function(d){
if(d.seatPic==null || d.seatPic=="")
return "尚未排座";
else
return "<img width='120px' src='"+d.seatPic+"'/>";
}
},
{field: '', title: '操作', width: 200,toolbar:'#tbar'},
]]
});
}
//点击查询
function query(){
table.reload('tb', {
url: $("#ctx").val()+'/info.action', //请求地址
method: 'POST', //请求方式,GET或者POST
loading: true, //是否显示加载条(默认 true)
page: true, //是否分页
where: { //设定异步数据接口的额外参数,任意设
'methodName':'myAudit',
'auditor':$('#auditor').val(),
'title':$('#title').val(),
},
request: { //自定义分页请求参数名
pageName: 'page', //页码的参数名称,默认:page
limitName: 'rows' //每页数据量的参数名,默认:limit
},
done: function (res, curr, count) {
console.log(res);
}
});
//工具条事件
table.on('tool(tb)', function(obj){ //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
row = obj.data; //获得当前行数据
var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值)
var tr = obj.tr; //获得当前行 tr 的 DOM 对象(如果有的话)
console.log(row);
if(layEvent === 'edit'){ //审批
openLayer(row.id);
} else {
}
});
}
// 打开审批页面
function openLayer(id){
layer.open({
type: 2, //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
title: '审批', //对话框标题
area: ['600px', '500px'], //宽高
skin: 'layui-layer-rim', //样式类名
content: $("#ctx").val()+'/jsp/meeting/addMeetingAudit.jsp', //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
btn:['审批通过','审批驳回'],
yes:function(index,layero){
//layer.msg('保存');
//调用子页面中提供的getData方法,快速获取子页面的form表单数据
let data= $(layero).find("iframe")[0].contentWindow.save();
data['meetingId']=id;
data['auditor']=$('#auditor').val();
addMeetingAudit(data);
},
btn2:function(){
let data={};
data['sign']=null;
data['meetingId']=id;
data['auditor']=$('#auditor').val();
addMeetingAudit(data);
return false;
}
});
}
// 添加审批意见
function addMeetingAudit(params){
params['methodName']="add";
console.log(params);
$.post($("#ctx").val()+'/audit.action',params,function(rs){
if(rs.success){
layer.closeAll();
query();
}else{
layer.msg(rs.msg,{icon:5},function(){});
}
},'json');
}
界面效果:


二、审批签字
1、审批签字我们需要借助一个在线绘图工具的插件,改造后引入我们的项目中。


接下来导入我们的项目中

界面效果:

2、 审批签字界面是会议审批界面的子界面,在会议审批的js方法中我们使用了find("iframe")的方法来调用子页面的data方法,快速获取子页面的表单数据
父页面js

子页面js

3、批处理:将审批人的意见数据入库并且修改会议状态

如图所示:
1、我们根据审批人点击通过按钮或者驳回按钮来判断 该会议为待开状态(也就是已通过)或者驳回状态。不论审批人点击的是哪个按钮我们都需要将该会议的最新状态添加进数据库中,因为这时该会议已经成为被审批过的会议了。当我们再次查询未审批会议时就不应该出现。
2、只有当会议状态为通过时才需要进行签字,驳回则无需签字。所以我们可以根据审批人是否签字来判断该会议的最新状态为待开或者驳回状态。同时我们也可以查看该会议入库时Sign字段也就是签字图片存放的路径是否为空,为空则是驳回状态,非空则是待开状态。
3、批处理:当审批人审批该会议后,该会议作为一条被审批过的会议添加进数据库中与修改会议状态的两条sql语句应当同时进行。就比如说A给B转账1000元,A的账户中减少1000元,B的账户中增加1000元,这两个事务应该同时进行,并且业务处理结果保持一致,要么转账成功A少B加,要么转账失败A,B账户余额都不发生改变。同理,如果某一条会议作为待开状态被加入数据库中,那么同时修改会议状态的这个事务处理该会议也同样为待开状态。
//批处理
public int add(MeetingAudit audit) {
// 将审批人的意见数据入库t_oa_meeting_audit
String sql1 = "insert into t_oa_meeting_audit(meetingid,auditor,sign)"
+ "values("+audit.getMeetingId()+","+audit.getAuditor()+",'"+audit.getSign()+"')";
//state状态有两种 审批通过即待开4,审批驳回即驳回状态3
//判断是否签字
boolean flag = StringUtils.isNotBlank(audit.getSign());
int state = flag?4:3;
//修改会议的状态 t_oa_meeting_info
String sql2 = " update t_oa_meeting_info set state=? where id ="+audit.getMeetingId();
//同时执行多个sql语句,其目的在于事务的一致性,要么业务处理同时成功,要么同时失败
return super.executeUpdateBatch(new String[] {sql1,sql2});
}4、签字图片裁剪
考虑到用户体验感以及美观度,在审批人签完字图片生成的过程中进行裁剪,使签字图片更美观,提升用户体验感。
*/
if(StringUtils.isNotBlank(audit.getSign())) {
String serverPathSign=PropertiesUtil.getValue("serverPathSign");
String dirPath=PropertiesUtil.getValue("dirPath");
//原图 图片名
String fileName1=UUID.randomUUID().toString().replace("-", "")+".png";
//裁剪后的图片名
String fileName2 = UUID.randomUUID().toString().replace("-", "")+".png";
//生成签字图片
Base64ImageUtils.GenerateImage(audit.getSign().replace("data:image/png;base64,",""),dirPath+fileName1 );
//将原图进行裁剪
ImageUtils.shearImg(dirPath+fileName1 , dirPath+fileName2);
//删除掉原图
File file = new File(dirPath+fileName1);
if(file.exists())
file.delete();
audit.setSign(serverPathSign+fileName2);
},
边栏推荐
- 勤于奋聊聊现在还有哪些副业可以做
- ELS compatibility DC, transfer pictures to window
- Final Cut Pro中文教程 (1) 基础认识Final Cut Pro
- .htaccess学习
- Wechat applet editor Avatar
- The usage syntax and scene of selector, as well as the usage of background picture size, text box shadow and excessive effect
- Hash table questions (Part 2)
- [dynamic planning hundred questions strengthening plan] 11~20 (continuously updating)
- Skywalking distributed system application performance monitoring tool - medium
- 【AtCoder Beginner Contest 260 (A·B·C)】
猜你喜欢

Final Cut Pro中文教程 (1) 基础认识Final Cut Pro

缓存读写策略:CacheAside、Read/WriteThrough及WriteBack策略

利用Power Automate,轻松下载Power BI报告中的数据

JS第二天(变量、变量的使用、命名规则、语法扩展)

VSCode开启Pull Request更新代码分支可视化新篇章

Structural mode - adapter mode

js小技巧

CDH cluster integration external Flink (improved version - keep pace with the times)

Interesting C language

Use unity to build a WordArt system
随机推荐
0动态规划中等 LeetCode467. 环绕字符串中唯一的子字符串
自定义视口高度,多余的部分使用滚动
ELS square display principle
js小技巧
Safety fourth after class exercise
[C language] dynamic memory management
STL 上头系列——list 容器详解
单元测试chapter6
打开编程的大门
5. Display of component dynamic components
Final review of management information system
HCIA static routing comprehensive experiment
在有序数组找具体某个数字
Simple static routing in ENSP
地平线 旭日X3 PI (四) 板上运行(未写完)
IIC communication protocol (I)
redux三大核心
HCIA dynamic routing rip basic experiment
[dynamic planning hundred questions strengthening plan] 11~20 (continuously updating)
结构型模式-适配器模式