目录
讲解思路
-
会议通知SQL语句分析
-
反馈详情SQL语句分析
-
后台代码编写
前端代码编写
效果预览
会议查询
MeetingFeedBack.java
package com.zking.oa.model;
import org.lisen.mvc.util.AutoIncrement;
import org.lisen.mvc.util.Key;
import org.lisen.mvc.util.Table;
import com.zking.oa.util.CacheUtil;
@Table("t_oa_meeting_feedback")
public class MeetiingFeedback {
@AutoIncrement
@Key
private Integer id;
private Integer meetingId;
private int personType;
private int personId;
private int result;
private String reason;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getMeetingId() {
return meetingId;
}
public void setMeetingId(Integer meetingId) {
this.meetingId = meetingId;
}
public int getPersonType() {
return personType;
}
public void setPersonType(int personType) {
this.personType = personType;
}
public int getPersonId() {
return personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public MeetiingFeedback(Integer id, Integer meetingId, int personType, int personId, int result, String reason) {
super();
this.id = id;
this.meetingId = meetingId;
this.personType = personType;
this.personId = personId;
this.result = result;
this.reason = reason;
}
public MeetiingFeedback() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "MeetiingFeedback [id=" + id + ", meetingId=" + meetingId + ", personType=" + personType + ", personId="
+ personId + ", result=" + result + ", reason=" + reason + "]";
}
/**
* 获取参与人员类型描述,是参与者还是列席者
* @return
*/
public String getMeetingJoinTypeName() {
return CacheUtil.getMeetingJoinType(this.personId);
}
/**
* 获取参与者名称
* @return
*/
public String getPersonName() {
return CacheUtil.getUser(this.getPersonId()).getName();
}
}
MeetingFeedBackDao.java
/**
* 会议通知:查询出我(当前登陆用户)需要参与的会议及会议的反馈信息(参会、缺席以及未读)
* @param back
* @param pageBean
* @return
* @throws SQLException
* @throws IllegalAccessException
* @throws InstantiationException
*/
@Override
public List<MeetiingFeedback> listMeetingFeedback(MeetiingFeedback meetingFeedback, PageBean pageBean) {
String sql = "SELECT t1.id,t1.meetingId, t1.personType, t1.personId, t1.result, t1.reason\r\n" +
" FROM t_oa_meeting_feedback t1\r\n" +
" WHERE 1=1 ";
List<Object> param = new ArrayList<Object>();
if(meetingFeedback != null && meetingFeedback.getResult()+"" != null) {
sql += " and t1.result = ? ";
param.add(meetingFeedback.getResult());
}
if(meetingFeedback != null && meetingFeedback.getMeetingId() != null) {
sql += " and t1.meetingId = ? ";
param.add(meetingFeedback.getMeetingId());
}
return DbTemplate.query(sql, param.toArray(), pageBean, MeetiingFeedback.class);
}
MeetingFeedBackAction.java
/**
* 查询会议相关人员的反馈信息
* @param req
* @param resp
*/
public void listMeetingFeedback(HttpServletRequest req, HttpServletResponse resp) {
try {
PageBean pageBean = new PageBean();
pageBean.setRequest(req);
List<MeetiingFeedback> list = service.listMeetingFeedback(meetingFeedback, pageBean);
CommonUtil.sendResponse(0, "会议反馈查询成功", pageBean.getTotal(), list, resp);
} catch (Exception e) {
e.printStackTrace();
CommonUtil.sendResponse(0, "会议反馈查失败", resp);
}
}
config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config[
<!ELEMENT config (action*)>
<!ELEMENT action (forward*)>
<!ELEMENT forward EMPTY>
<!ATTLIST action
path CDATA #REQUIRED
type CDATA #REQUIRED
>
<!ATTLIST forward
name CDATA #REQUIRED
path CDATA #REQUIRED
redirect (true|false) "false"
>
]>
<config>
<action type="com.zking.oa.action.UserAction" path="/userAction"> </action>
<action type="com.zking.oa.action.PermissionAction" path="/permissionAction"> </action>
<action type="com.zking.oa.action.MeetinginfoAction" path="/meetinginfoAction"> </action>
<action type="com.zking.oa.action.MeetingAuditAction" path="/meetingAuditAction"> </action>
<action type="com.zking.oa.action.meetingFeedbackAction" path="/meetingFeedbackAction"> </action>
</config>
DateUtil.java
package com.zking.oa.util;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日期帮助类
* @author lisensir
*/
public final class DateUtil {
private DateUtil() {}
private static final String FORMCAT_STR = "yyyy-MM-dd HH:mm:ss";
/**
* 将日期格式化为yyyy-MM-dd HH:mm:ss格式的字符串
* @param date 需要格式化的日期
* @return
*/
public static String format(Date date) {
if(date == null) return "";
SimpleDateFormat sdf = new SimpleDateFormat(FORMCAT_STR);
return sdf.format(date);
}
/**
* 将日期格式化为yyyy-MM-dd HH:mm:ss格式的字符串
* @param date 需要格式化的日期
* @param format 指定的格式字符串
* @return
*/
public static String format(Date date, String format) {
if(date == null) return "";
SimpleDateFormat sdf = new SimpleDateFormat(format);
return sdf.format(date);
}
public static void main(String[] args) {
Date date = new Date(System.currentTimeMillis());
String s = format(date);
System.out.println(s);
}
}
meetingNotify.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="/common/head.jsp" %>
<title>会议通知</title>
<style>
.layui-inline {
margin-top: 20px;
}
.seatPicDiv {
height: 180px;
}
.seatPic:active {
height: 360px;
}
.layui-layer-page .layui-layer-content {
/* 解决送审对话框中人员选择下拉框不能完全显示问题 */
overflow: visible;!important
}
</style>
</head>
<body>
<!-- 查询条件 -->
<div class="layui-inline">
<label class="layui-form-label">标题:</label>
<div class="layui-input-block">
<input type="text" name="title" id="title" placeholder="会议标题" class="layui-input">
</div>
</div>
<div class="layui-inline">
<button class="layui-btn" id="queryMeetingInfo"><i class="layui-icon layui-icon-search"></i>查询</button>
</div>
<!-- 用户信息表格 -->
<table class="layui-hide" id="meetingInfoTable" lay-filter="meetingInfoTable"></table>
<!-- 使用了layui自定义语法,当会议不能送审或排座时将按钮显示为禁用状态 -->
<script type="text/html" id="toolbar">
<button class="layui-btn layui-btn-sm" lay-event="feeback">反馈</button>
</script>
</body>
</html>
meetingNotify.js
<script>
let table=null;
let $ = null;
var row = null;
let formSelects = null;
let form = null;
let layer = null;
layui.use(['table','jquery','formSelects','form','layer'], function(){
table = layui.table;
$ = layui.jquery;
formSelects = layui.formSelects;
form = layui.form;
layer = layui.layer;
loadMeetingInfo();
//查询我的会议信息
$("#queryMeetingInfo").click(function() {
loadMeetingInfo();
});
//对表格的功能按钮增加事件监听,如排座,送审,反馈按钮
table.on('tool(meetingInfoTable)', function(obj) {
if(obj.event == 'feeback') {
openFeebackDialog(obj.data);
}
});
});
var row = null;
function openFeebackDialog(data) {
row = data;
layer.open({
type: 2, //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
title:'会议反馈',
area: ['654px', '420px'], //宽高
skin: 'layui-layer-rim', //样式类名
content: ctx + '/jsp/meeting/addFeedBack.jsp', //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
btn: ['确定', '关闭'],
yes: function(index,layero) {
let formData = $(layero).find("iframe")[0].contentWindow.getFormData();
console.log(formData);
addMeetingFeedback(formData);
},
btn2: function(index,layero){
}
});
}
//查询会议信息
function loadMeetingInfo() {
table.render({
elem: '#meetingInfoTable',
url: ctx + '/meetinginfoAction.action?methodName=listRelatedMeetingInfoByUserId',
cols: [[
{field:'id', width:80, title: 'ID'},
{field:'title', width:180, title: '会议标题', sort: true},
{field:'location', width:180, title: '会议地点', sort: true},
{field:'startTime', width:180, title: '开始时间'},
{field:'endTime', width:180, title: '结束时间'},
{field:'meetingState', width:180, title: '会议状态'},
{fixed:'right', title: '操作', width:200, align:'left', unresize: true, toolbar:'#toolbar'}
]],
page: true,
request: {
pageName: 'page',
limitName: 'rows'
},
method: 'post',
where: {
title: $("#title").val()
},
loading: true,
});
}
</script>
是否参会
MeetingFeedBackDao.java
/**
* 新增会议反馈
* @param back
*/
public void addMeetingFeedback(MeetiingFeedback back) {
String sql="insert into t_oa_meeting_feedback(meetingId,personType,personId,result,reason) values(?,?,?,?,?)";
super.executeUpdate(sql, new Object[] {
back.getMeetingId(),
back.getPersonType(),
back.getPersonId(),
back.getResult(),
back.getReason()
});
}
MeetingFeedBackAction.java
/**
* 增加会议反馈
* @param req
* @param resp
*/
public void addMeetingFeedback(HttpServletRequest req, HttpServletResponse resp) {
try {
service.addMeetingFeedback(meetingFeedback);
CommonUtil.sendResponse(0, "会议反馈成功", resp);
} catch (Exception e) {
e.printStackTrace();
CommonUtil.sendResponse(0, "会议反馈失败", resp);
}
}
meetingNotify.js
<script>
let table=null;
let $ = null;
var row = null;
let formSelects = null;
let form = null;
let layer = null;
layui.use(['table','jquery','formSelects','form','layer'], function(){
table = layui.table;
$ = layui.jquery;
formSelects = layui.formSelects;
form = layui.form;
layer = layui.layer;
loadMeetingInfo();
//查询我的会议信息
$("#queryMeetingInfo").click(function() {
loadMeetingInfo();
});
//对表格的功能按钮增加事件监听,如排座,送审,反馈按钮
table.on('tool(meetingInfoTable)', function(obj) {
if(obj.event == 'feeback') {
openFeebackDialog(obj.data);
}
});
});
var row = null;
function openFeebackDialog(data) {
row = data;
layer.open({
type: 2, //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
title:'会议反馈',
area: ['654px', '420px'], //宽高
skin: 'layui-layer-rim', //样式类名
content: ctx + '/jsp/meeting/addFeedBack.jsp', //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
btn: ['确定', '关闭'],
yes: function(index,layero) {
let formData = $(layero).find("iframe")[0].contentWindow.getFormData();
console.log(formData);
addMeetingFeedback(formData);
},
btn2: function(index,layero){
}
});
}
//增加会议反馈
function addMeetingFeedback(param) {
$.ajax({
url: ctx + "/meetingFeedbackAction.action?methodName=addMeetingFeedback",
data: param,
type: 'post',
dataType: 'json',
success: function(resp) {
layer.msg(resp.msg,{
icon: 1,
time: 2000 //2秒关闭(如果不配置,默认是3秒)
},function() {
layer.closeAll();
});
}
});
}
//查询会议信息
function loadMeetingInfo() {
table.render({
elem: '#meetingInfoTable',
url: ctx + '/meetinginfoAction.action?methodName=listRelatedMeetingInfoByUserId',
cols: [[
{field:'id', width:80, title: 'ID'},
{field:'title', width:180, title: '会议标题', sort: true},
{field:'location', width:180, title: '会议地点', sort: true},
{field:'startTime', width:180, title: '开始时间'},
{field:'endTime', width:180, title: '结束时间'},
{field:'meetingState', width:180, title: '会议状态'},
{fixed:'right', title: '操作', width:200, align:'left', unresize: true, toolbar:'#toolbar'}
]],
page: true,
request: {
pageName: 'page',
limitName: 'rows'
},
method: 'post',
where: {
title: $("#title").val()
},
loading: true,
});
}
</script>
addFeedBack.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<%@include file="/common/head.jsp" %>
</head>
<style>
body{
margin:5px;
}
</style>
<body>
<div style="padding:10px;">
<!-- 反馈表单 -->
<form class="layui-form layui-form-pane" lay-filter="back">
<input type="hidden" name="meetingId" id="meetingId"/>
<input type="hidden" name="personId" value="${sessionScope.user.id }"/>
<div class="layui-form-item">
<label class="layui-form-label">人员类型</label>
<div class="layui-input-block">
<!--
<select id="personType" name="personType">
<option value="">请选择人员类型</option>
<option value="1">参会</option>
<option value="2">列席</option>
</select> -->
<input type="hidden" name="personType" id="personType"/>
<input type="text" id="personTypeName" autocomplete="off" readonly="readonly" class="layui-input">
</div>
</div>
<div class="layui-form-item" pane="">
<label class="layui-form-label">反馈结果</label>
<div class="layui-input-block" >
<!--
<select id="result" name="result">
<option value="">请选择反馈结果</option>
<option value="1">参加</option>
<option value="2">不参加</option>
</select> -->
<input type="radio" name="result" value="1" title="参加" checked>
<input type="radio" name="result" value="2" title="不参加">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">不参与会议的原因</label>
<div class="layui-input-block">
<textarea placeholder="请输入内容" name="reason" class="layui-textarea"></textarea>
</div>
</div>
</form>
</div>
</body>
</html>
addFeedBack.js
<script>
let form = null;
layui.use(['jquery', 'form'], function() {
let $ = layui.$;
form = layui.form;
//获取会议记录信息
let data = parent.row || {};
//获取当前登录用户ID
let currentUserId = '${sessionScope.user.id}';
//设置会议ID
$("#meetingId").val(data.id);
//判断当前用户是存在与参与者中,如果是则设置人员类型为参与者
let canyuze = data.canyuze.split(",");
if(canyuze.indexOf(currentUserId) > -1) {
$("#personTypeName").val("参与者");
$("#personType").val("1");
}
//判断当前用户是存在与列席者中,如果是则设置人员类型为列席者
let liexize = data.liexize.split(",");
if(liexize.indexOf(currentUserId) > -1) {
$("#personTypeName").val("列席者");
$("#personType").val("2");
}
});
//获取表单数据,在父窗口(会议通知)会调用该方法获取表单数据用于提交
function getFormData() {
return form.val('back');
}
</script>
反馈详情
MeetingFeedBackDao.java
/**
* 根据会议ID获取会议反馈详情信息
* @param back
* @return
*/
@SuppressWarnings("unchecked")
public List<Map<String,Object>> queryBackPersons(MeetiingFeedback back){
String sql="select " +
"f.result,GROUP_CONCAT(u.name) as name " +
"from " +
"t_oa_meeting_feedback f,t_oa_user u " +
"where f.personId=u.id and meetingId="+back.getMeetingId()+" group by f.result";
System.out.println(sql);
return super.executeQuery(sql, null, new convert<Map<String,Object>>() {
@Override
public List<Map<String, Object>> forEach(ResultSet rs) throws Exception {
return CommonUtils.toList(rs);
}
});
}
MeetingFeedBackAction.java
/**
* 查询会议相关人员的反馈信息
* @param req
* @param resp
*/
public void listMeetingFeedback(HttpServletRequest req, HttpServletResponse resp) {
try {
PageBean pageBean = new PageBean();
pageBean.setRequest(req);
List<MeetiingFeedback> list = service.listMeetingFeedback(meetingFeedback, pageBean);
CommonUtil.sendResponse(0, "会议反馈查询成功", pageBean.getTotal(), list, resp);
} catch (Exception e) {
e.printStackTrace();
CommonUtil.sendResponse(0, "会议反馈查失败", resp);
}
}
myMeeting.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<%@ include file="/common/head.jsp" %>
<title>Insert title here</title>
<style>
.layui-inline {
margin-top: 20px;
}
.seatPicDiv {
height: 180px;
}
.seatPic:active {
height: 360px;
}
.layui-layer-page .layui-layer-content {
/* 解决送审对话框中人员选择下拉框不能完全显示问题 */
overflow: visible;!important
}
</style>
</head>
<body>
<!-- 查询条件 -->
<div class="layui-inline">
<label class="layui-form-label">标题:</label>
<div class="layui-input-block">
<input type="text" name="title" id="title" placeholder="会议标题" class="layui-input">
</div>
</div>
<div class="layui-inline">
<button class="layui-btn" id="queryMeetingInfo"><i class="layui-icon layui-icon-search"></i>查询</button>
</div>
<!-- 用户信息表格 -->
<table class="layui-hide" id="meetingInfoTable" lay-filter="meetingInfoTable"></table>
<!-- 使用了layui自定义语法,当会议不能送审或排座时将按钮显示为禁用状态 -->
<script type="text/html" id="toolbar">
{{# if(d.state==1 || d.state==3){ }}
<button class="layui-btn layui-btn-sm" lay-event="seat">排座</button>
<button class="layui-btn layui-btn-sm" lay-event="send">送审</button>
{{# } else{ }}
<button class="layui-btn layui-btn-sm layui-btn-disabled" lay-event="seat">排座</button>
<button class="layui-btn layui-btn-sm layui-btn-disabled" lay-event="send">送审</button>
{{# } }}
<button class="layui-btn layui-btn-sm" lay-event="feedback">反馈</button>
</script>
<!-- 送审对话框内容 -->
<div id="auditDiv" style="display:none;">
<form style="margin:20px 15px;" class="layui-form layui-form-pane" id="sendAudit" lay-filter="sendAudit">
<div class="layui-inline">
<label class="layui-form-label">送审人</label>
<div class="layui-input-inline">
<select name="auditPerson" xm-select="auditPerson" xm-select-radio>
<option value="" disabled="disabled">--请选择--</option>
</select>
</div>
<div class="layui-input-inline">
<!-- <button id="btn_auditor" class="layui-btn" lay-filter="sendAudit">送审</button> -->
<button type="button" id="sendAudit" lay-submit lay-filter="sendAudit" class="layui-btn layui-btn-normal">送审</button>
</div>
</div>
</form>
</div>
</body>
</html>
myMeeting.js
<script>
let table=null;
let $ = null;
var row = null;
let formSelects = null;
let form = null;
let layer = null;
layui.use(['table','jquery','formSelects','form','layer'], function(){
table = layui.table;
$ = layui.jquery;
formSelects = layui.formSelects;
form = layui.form;
layer = layui.layer;
loadMeetingInfo();
//查询我的会议信息
$("#queryMeetingInfo").click(function() {
loadMeetingInfo();
});
//对表格的功能按钮增加事件监听,如排座,送审,反馈按钮
table.on('tool(meetingInfoTable)', function(obj) {
//排座
if(obj.event == 'seat') {
//对于新建或驳回状态的会议可以执行排座
if(obj.data.state == 1 || obj.data.state == 3) {
openSeatPic(obj.data.id);
} else {
layer.msg("对于审核通过,结束,取消,进行中等状态的会议不能再执行排座")
}
}
//送审
if(obj.event == 'send') {
if(obj.data.seatPic) {
//对于新建或驳回状态的会议可以送审
if(obj.data.state == 1 || obj.data.state == 3) {
openSendAudit(obj.data.id);
} else {
layer.msg("对于审核通过,结束,取消,进行中等状态的会议不能执行送审");
}
} else {
layer.msg("未进行排座不能送审");
}
}
//查看反馈
if(obj.event == 'feedback') {
openFeedbackInfo(obj.data);
}
});
});
function openFeedbackInfo(data) {
let ignore = [0,1,2,3];
if(ignore.indexOf(data.state) >= 0) {
layer.msg("对于新建、驳回、取消、待审状态下的会议,不用查看反馈");
return;
}
debugger;
layer.open({
type: 2, //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
title:'反馈详情',
area: ['600px', '650px'], //宽高
skin: 'layui-layer-rim', //样式类名
content: ctx+'/jsp/meeting/meetingFeedback.jsp?meetingId=' + data.id,
btn:['关闭'],
yes:function(index,layero){
layer.closeAll();
}
});
}
// 打开送审的对话框,执行送审
function openSendAudit(id) {
let index = layer.open({
type: 1, //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
title: '送审',
area: ['660px', '200px'], //宽高
skin: 'layui-layer-rim', //样式类名
content: $("#auditDiv") //送审对应的div
});
//初始化送审人员选择下拉列表的数据
formSelects.data('auditPerson', 'server', {
url: ctx + '/meetinginfoAction.action?methodName=listMeetingMember'
});
//添加送审按钮的监听事件,发送ajax请求执行送审
form.on('submit(sendAudit)', function(data) {
console.log(data);
data.field["id"] = id;
console.log(data);
$.ajax({
url: ctx + '/meetinginfoAction.action?methodName=sendAudit',
data: data.field,
type: 'post',
dataType: 'json',
success: function(resp) {
layer.msg(resp.msg);
layer.close(index);
//送审成功,更新我的会议列表
loadMeetingInfo();
}
})
});
}
//会议排座
function openSeatPic(id) {
row = null;
layer.open({
type: 2, //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
title: '会议排座',
area: ['660px', '350px'], //宽高
skin: 'layui-layer-rim', //样式类名
content: ctx+'/jsp/meeting/seatPic.jsp?id='+id
});
};
//查询会议信息
function loadMeetingInfo() {
table.render({
elem: '#meetingInfoTable',
url: ctx + '/meetinginfoAction.action?methodName=listMeetingInfo',
cols: [[
{field:'id', width:60, title: 'ID'},
{field:'title', width:180, title: '会议标题', sort: true},
{field:'location', width:180, title: '会议地点', sort: true},
{field:'startTime', width:160, title: '开始时间'},
{field:'endTime', width:160, title: '结束时间'},
{field:'meetingState', width:180, title: '会议状态'},
//显示排座图片
{field: 'seatPic', title: '会议排座', width: 180,
templet:function(d){
if(null==d.seatPic)
return "尚未排座";
else
return "<img height='180px' src='"+d.seatPic+"'/>";
}
},
{field: '', title: '操作', width: 250, toolbar:'#toolbar'}
]],
page: true,
request: {
pageName: 'page',
limitName: 'rows'
},
method: 'post',
where: {
title: $("#title").val()
},
loading: true,
});
}
</script>