• 会议OA之会议排座&送审


    目录

    最近这段时间一直都在与大家分享会议OA项目,今天继续分享关于会议OA项目的一个亮点功能,会议排座。以及一个送审功能。

    一、会议排座

    二、送审


    最近这段时间一直都在与大家分享会议OA项目,今天继续分享关于会议OA项目的一个亮点功能,会议排座。以及一个送审功能。

    一、会议排座

    1、会议排座插件

    为了实现会议排座功能,我们需要再网上寻找一个会议排座的插件。可以上百度搜索

     在网上找到的一个插件,但是发现了以下两个问题:

    ①、发现元素重叠,无法判定有几个人参会 ②、元素块太小看不清

    所以我们不能直接使用素材,需要改造以适用于我们的项目

    改造后:

    源代码:

    1. <html>
    2. <head>
    3. <title>会议座位安排title>
    4. <style type="text/css">
    5. * {
    6. padding: 0;
    7. margin: 0;
    8. }
    9. .tips {
    10. /* position: absolute; */
    11. background: #eee;
    12. display: inline-block;
    13. height: 60px;
    14. width: 60px;
    15. line-height: 60px;
    16. text-align: center;
    17. margin: 5px;
    18. }
    19. .add {
    20. position: fixed;
    21. right: 0;
    22. top: 0
    23. }
    24. #tu {
    25. width: 564px;
    26. height: 330px;
    27. background: lightblue
    28. /*background: url('u=3318199716,2583790385&fm=26&gp=0.jpg');*/
    29. }
    30. style>
    31. <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js">script>
    32. <script type="text/javascript" src="http://html2canvas.hertzen.com/dist/html2canvas.js">script>
    33. head>
    34. <body>
    35. <div id="tu">div>
    36. <div class="add">
    37. <input id="dan_input" type="text" value="">
    38. <button onclick="return addDanMu()">添加座位button>
    39. <input id="jie_input" type="button" value='下载'>
    40. div>
    41. body>
    42. <script type="text/javascript">
    43. var $id = function(id) {
    44. return document.getElementById(id);
    45. }
    46. var dragF = {
    47. locked: false,
    48. lastObj: undefined,
    49. drag: function(obj) {
    50. $id(obj).onmousedown = function(e) {
    51. var e = e ? e : window.event;
    52. if (!window.event) {
    53. e.preventDefault();
    54. } /* 阻止标注浏览器下拖动a,img的默认事件 */
    55. dragF.locked = true;
    56. $id(obj).style.position = "absolute";
    57. $id(obj).style.zIndex = "100";
    58. if (dragF.lastObj && dragF.lastObj != $id(obj)) { /* 多元素拖动需要恢复上次元素状态 */
    59. dragF.lastObj.style.zIndex = "1";
    60. }
    61. dragF.lastObj = $id(obj);
    62. var tempX = $id(obj).offsetLeft;
    63. var tempY = $id(obj).offsetTop;
    64. dragF.x = e.clientX;
    65. dragF.y = e.clientY;
    66. document.onmousemove = function(e) {
    67. var e = e ? e : window.event;
    68. if (dragF.locked == false) return false;
    69. $id(obj).style.left = tempX + e.clientX - dragF.x + "px";
    70. $id(obj).style.top = tempY + e.clientY - dragF.y + "px";
    71. if (window.event) {
    72. e.returnValue = false;
    73. } /* 阻止ie下a,img的默认事件 */
    74. }
    75. document.onmouseup = function() {
    76. dragF.locked = false;
    77. }
    78. }
    79. }
    80. }
    81. script>
    82. <script>
    83. function addDanMu() {
    84. var dan = document.getElementById("dan_input").value;
    85. if (dan == "") {
    86. alert("请输入弹幕~");
    87. return false;
    88. } else {
    89. document.getElementById("dan_input").value = ""; //清空 弹幕输入框
    90. // var br = document.createElement("BR"); //
    91. var node = document.createElement("DIV"); //
    92. var tipsArr = document.getElementsByClassName('tips');
    93. var i;
    94. // console.log(parseInt(tipsArr[tipsArr.length-1].id.substr(4))+1);
    95. if (tipsArr.length == 0) {
    96. i = 1
    97. } else {
    98. i = parseInt(tipsArr[tipsArr.length - 1].id.substr(4)) + 1;
    99. }
    100. // var aNode = document.createElement("P"); //

    101. node.setAttribute("class", "tips");
    102. node.setAttribute("id", "tips" + i);
    103. node.setAttribute("onmouseover", "dragF.drag('tips" + i + "');");
    104. var textnode = document.createTextNode(dan); // 创建个 文本节点, 将用户输入的弹幕,存入 创建的 元素节点

    105. // aNode.appendChild(textnode);
    106. node.appendChild(textnode);
    107. // document.body.appendChild(br);
    108. // document.body.appendChild(node);
    109. document.getElementById("tu").appendChild(node);
    110. return true;
    111. }
    112. }
    113. script>
    114. <script type="text/javascript">
    115. $("#jie_input").on("click", function(event) {
    116. event.preventDefault();
    117. html2canvas(document.getElementById("tu")).then(function(canvas) {
    118. var dataUrl = canvas.toDataURL();
    119. var newImg = document.createElement("img");
    120. newImg.src = dataUrl;
    121. // document.body.appendChild(newImg);
    122. // console.log(dataUrl)
    123. this.downloadFile('测试.png', dataUrl);
    124. });
    125. });
    126. //下载
    127. function downloadFile(fileName, content) {
    128. debugger;
    129. let aLink = document.createElement('a');
    130. let blob = this.base64ToBlob(content); //new Blob([content]);
    131. let evt = document.createEvent("HTMLEvents");
    132. evt.initEvent("click", true, true); //initEvent 不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为
    133. aLink.download = fileName;
    134. aLink.href = URL.createObjectURL(blob);
    135. // aLink.dispatchEvent(evt);
    136. //aLink.click()
    137. aLink.dispatchEvent(new MouseEvent('click', {
    138. bubbles: true,
    139. cancelable: true,
    140. view: window
    141. })); //兼容火狐
    142. }
    143. //base64转blob
    144. function base64ToBlob(code) {
    145. let parts = code.split(';base64,');
    146. let contentType = parts[0].split(':')[1];
    147. let raw = window.atob(parts[1]);
    148. let rawLength = raw.length;
    149. let uInt8Array = new Uint8Array(rawLength);
    150. for (let i = 0; i < rawLength; ++i) {
    151. uInt8Array[i] = raw.charCodeAt(i);
    152. }
    153. return new Blob([uInt8Array], {
    154. type: contentType
    155. });
    156. }
    157. script>
    158. html>

    2、将会议排座插件运用到项目中

    我们需要将会议排座以html的格式转换为jsp页面,同时当我们点击会议排座时,能够弹出会议排座这个页面

    2.1会议排座jsp页面

    1. <%@ page language="java" contentType="text/html; charset=UTF-8"
    2. pageEncoding="UTF-8"%>
    3. html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    4. <html>
    5. <head>
    6. <base href="${pageContext.request.contextPath }/"/>
    7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    8. <link href="static/js/layui/css/layui.css" rel="stylesheet" type="text/css"/>
    9. <script type="text/javascript" src="static/js/jquery-3.3.1.min.js">script>
    10. <script type="text/javascript" src="static/js/layui/layui.js">script>
    11. <script type="text/javascript" src="static/js/plugins/html2canvas/html2canvas.js">script>
    12. <title>会议座位安排title>
    13. head>
    14. <style type="text/css">
    15. * {
    16. padding: 0;
    17. margin: 0;
    18. }
    19. body{
    20. width: 100%;
    21. height: 100%;
    22. /* background: red; */
    23. }
    24. .tips {
    25. /* position: absolute; */
    26. background: pink;
    27. display: inline-block;
    28. height: 60px;
    29. /* width: 60px; */
    30. line-height: 60px;
    31. text-align: center;
    32. margin: 5px;
    33. padding: 0 10px;
    34. }
    35. .add {
    36. position: fixed;
    37. right: 10px;
    38. top: 10px;
    39. display:inline;
    40. }
    41. #tu {
    42. width: 100%;
    43. height: 100%;
    44. /* background: lightblue; */
    45. /*background: url('u=3318199716,2583790385&fm=26&gp=0.jpg');*/
    46. }
    47. .layui-input{
    48. height:30px;
    49. }
    50. style>
    51. <body id="screen_body">
    52. <div id="tu">div>
    53. <div class="add">
    54. <div style="display:inline-block;">
    55. <input id="dan_input" type="text" value="" class="layui-input">
    56. div>
    57. <div style="display:inline-block;">
    58. <button onclick="return addDanMu()" class="layui-btn layui-btn-sm">添加座位button><input id="jie_input" type="button" class="layui-btn layui-btn-sm" value='下载'>
    59. div>
    60. div>
    61. body>
    62. <script type="text/javascript">
    63. var $id = function(id) {
    64. return document.getElementById(id);
    65. }
    66. //会议排座拖拽
    67. var dragF = {
    68. locked: false,
    69. lastObj: undefined,
    70. drag: function(obj) {
    71. $id(obj).onmousedown = function(e) {
    72. var e = e ? e : window.event;
    73. if (!window.event) {
    74. e.preventDefault();
    75. } /* 阻止标注浏览器下拖动a,img的默认事件 */
    76. dragF.locked = true;
    77. $id(obj).style.position = "absolute";
    78. $id(obj).style.zIndex = "100";
    79. if (dragF.lastObj && dragF.lastObj != $id(obj)) { /* 多元素拖动需要恢复上次元素状态 */
    80. dragF.lastObj.style.zIndex = "1";
    81. }
    82. dragF.lastObj = $id(obj);
    83. var tempX = $id(obj).offsetLeft;
    84. var tempY = $id(obj).offsetTop;
    85. dragF.x = e.clientX;
    86. dragF.y = e.clientY;
    87. document.onmousemove = function(e) {
    88. var e = e ? e : window.event;
    89. if (dragF.locked == false) return false;
    90. $id(obj).style.left = tempX + e.clientX - dragF.x + "px";
    91. $id(obj).style.top = tempY + e.clientY - dragF.y + "px";
    92. if (window.event) {
    93. e.returnValue = false;
    94. } /* 阻止ie下a,img的默认事件 */
    95. }
    96. document.onmouseup = function() {
    97. dragF.locked = false;
    98. }
    99. }
    100. }
    101. }
    102. script>
    103. <script type="text/javascript">
    104. var layer;
    105. layui.use(['layer'],function(){
    106. layer=layui.layer;
    107. //初始化会议排座:根据会议ID获取参会的所有人员的名字(主持人+参会人+列席人)
    108. initMeetingUsers();
    109. //绘制会议排座图片
    110. $("#jie_input").on("click", function(event) {
    111. $('.add').hide();
    112. event.preventDefault();
    113. html2canvas(document.getElementById("screen_body")).then(function(canvas) {
    114. var dataUrl = canvas.toDataURL();
    115. console.log(dataUrl);
    116. var param = {};
    117. param['seatPic'] = dataUrl;
    118. param['id'] = '${param.id}';
    119. param['methodName']='updateSeatPicById';
    120. console.log(param);
    121. //此处需要完成会议排座图片上传操作
    122. $.post('${pageContext.request.contextPath }/info.action',param,function(rs){
    123. if(rs.success){
    124. //先得到当前iframe层的索引
    125. var index = parent.layer.getFrameIndex(window.name);
    126. //再执行关闭
    127. parent.layer.close(index);
    128. //调用父页面的刷新方法
    129. parent.query();
    130. }else{
    131. layer.msg(rs.msg,{icon:5},function(){});
    132. }
    133. },'json');
    134. });
    135. });
    136. });
    137. function initMeetingUsers(){
    138. //http://localhost:8080/xxx/seatPic.jsp?id=12 -> ${param.id}
    139. $.getJSON('${pageContext.request.contextPath }/user.action',{
    140. 'methodName':'queryUserByMeetingId',
    141. 'meetingId':'${param.id}'
    142. },function(rs){
    143. console.log(rs);
    144. let data=rs.data;
    145. $.each(data,function(i,e){
    146. $('#dan_input').val(e.name);
    147. addDanMu();
    148. });
    149. });
    150. }
    151. //添加会议排座
    152. function addDanMu() {
    153. var dan = document.getElementById("dan_input").value;
    154. if (dan == "") {
    155. alert("请输入弹幕~");
    156. return false;
    157. } else {
    158. document.getElementById("dan_input").value = ""; //清空 弹幕输入框
    159. // var br = document.createElement("BR"); //
    160. var node = document.createElement("DIV"); //
    161. var tipsArr = document.getElementsByClassName('tips');
    162. var i;
    163. // console.log(parseInt(tipsArr[tipsArr.length-1].id.substr(4))+1);
    164. if (tipsArr.length == 0) {
    165. i = 1
    166. } else {
    167. i = parseInt(tipsArr[tipsArr.length - 1].id.substr(4)) + 1;
    168. }
    169. // var aNode = document.createElement("P"); //

    170. node.setAttribute("class", "tips");
    171. node.setAttribute("id", "tips" + i);
    172. node.setAttribute("onmouseover", "dragF.drag('tips" + i + "');");
    173. var textnode = document.createTextNode(dan); // 创建个 文本节点, 将用户输入的弹幕,存入 创建的 元素节点

    174. // aNode.appendChild(textnode);
    175. node.appendChild(textnode);
    176. // document.body.appendChild(br);
    177. // document.body.appendChild(node);
    178. document.getElementById("tu").appendChild(node);
    179. return true;
    180. }
    181. }
    182. script>
    183. html>

    2.2在我的会议js代码中添加打开会议排座的ajax方法 layer.open

    1. //打开会议排座对话框
    2. function open(id){
    3. layer.open({
    4. type: 2, //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
    5. title: '会议排座', //对话框标题
    6. area: ['460px', '340px'], //宽高
    7. skin: 'layui-layer-rim', //样式类名
    8. content: $("#ctx").val()+'/jsp/meeting/seatPic.jsp?id='+id, //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
    9. });
    10. }

     2.3运行效果:

    3、会议参会用户数据 初始化

    现在我们已经成功将插件运用到项目中,但是实际上该会议的参会者数据我们应该拿到并且绑定在会议排座的界面上,然后在拖动元素进行排座。

    3.1编写SQL语句

    SQL语句对比

     

     

    使用函数Find_in_set

     

     

    1. select * from t_oa_user where FIND_IN_SET(id,"
    2. + "(select concat(canyuze,',',liexize,',',zhuchiren) uid "
    3. + "from t_oa_meeting_info where id="+meetingId+"))

    3.2后台编码

    userDao

    1. public List queryUserByMeetingId(Long meetingId) throws Exception{
    2. String sql="select * from t_oa_user where FIND_IN_SET(id,"
    3. + "(select concat(canyuze,',',liexize,',',zhuchiren) uid "
    4. + "from t_oa_meeting_info where id="+meetingId+"))";
    5. return super.executeQuery(sql, User.class, null);
    6. }

    userAction

    1. public String queryUserByMeetingId(HttpServletRequest req,HttpServletResponse resp) throws Exception{
    2. try {
    3. String meetingId = req.getParameter("meetingId");
    4. List users = userDao.queryUserByMeetingId(Long.valueOf(meetingId));
    5. CommonUtils.toJson(true, users, resp);
    6. } catch (Exception e) {
    7. CommonUtils.toJson(false,"获取参会人员信息失败", resp);
    8. e.printStackTrace();
    9. }
    10. return null;
    11. }

    错误提示:记得记得记得记得一定要导入jquery类库 ,,不然无法将数据显示在会议排座界面上

     

     

    4、生成会议排座图片

    4.1meetinginfoDao

    1. // 根据会议ID更新会议的排座图片
    2. public int updateSeatPicById(MeetingInfo info) throws Exception {
    3. String sql="update t_oa_meeting_info set seatPic=? where id=?";
    4. return super.executeUpdate(sql, info, new String[] {"seatPic","id"});
    5. }

    4.2meetinginfoAction

    1. // 根据会议id更新排座
    2. public String updateSeatPicById(HttpServletRequest req,
    3. HttpServletResponse resp) throws Exception{
    4. try {
    5. //1.将排座图片保存到指定的位置并得到图片路径
    6. //1) 定义会议图片的保存路径
    7. String serverPath=PropertiesUtil.getValue("serverPath");
    8. String dirPath=PropertiesUtil.getValue("dirPath");
    9. //2) 定义会议排座图片的名称(最终要保存到数据库表中),例如:/uploads/xxxxx.jpg
    10. String fileName=UUID.randomUUID().toString().replace("-", "")+".jpg";
    11. //3) 拼接成完整的路径
    12. String realPath=dirPath+fileName;
    13. //4) 将图片保存到指定位置
    14. Base64ImageUtils.GenerateImage(info.getSeatPic().replace("data:image/png;base64,",""), realPath);
    15. //2.根据会议ID修改会议图片信息
    16. info.setSeatPic(serverPath+fileName);
    17. infoDao.updateSeatPicById(info);
    18. ResponseUtil.writeJson(resp, R.ok(200, "更新会议的排座图片成功"));
    19. } catch (Exception e) {
    20. e.printStackTrace();
    21. try {
    22. ResponseUtil.writeJson(resp, R.error(0, "更新会议的排座图片失败"));
    23. } catch (Exception e1) {
    24. e1.printStackTrace();
    25. }
    26. }
    27. return null;
    28. }

     点击下载然后就能显示在我们本地的E盘上并且能够在界面上显示

     

     

     

     

    二、送审

     

    1、后台编码

    1.1meetinginfoDao

    1. // 根据会议ID更新会议的审批人(送审)
    2. public int updateAuditorById(MeetingInfo info) throws Exception {
    3. String sql="update t_oa_meeting_info set auditor=?,state=2 where id=?";
    4. return super.executeUpdate(sql, info, new String[] {"auditor","id"});
    5. }

    1.2meetinginfoAction

    1. // 根据会议ID更新会议的审批人(送审)
    2. public String updateAuditorById(HttpServletRequest req, HttpServletResponse resp) {
    3. try {
    4. int rs = infoDao.updateAuditorById(info);
    5. if (rs > 0) {
    6. ResponseUtil.writeJson(resp, R.ok(200, "会议审批成功"));
    7. }else {
    8. ResponseUtil.writeJson(resp, R.error(0, "会议审批失败"));
    9. }
    10. } catch (Exception e) {
    11. e.printStackTrace();
    12. try {
    13. ResponseUtil.writeJson(resp, R.error(0, "会议审批失败"));
    14. } catch (Exception e1) {
    15. e1.printStackTrace();
    16. }
    17. }
    18. return null;
    19. }

    2、前台编码

    meetinginfo.js

    1. //会议送审
    2. function openLayerAudit(){
    3. //每次打开都对送审人进行初始化默认值设置
    4. $('#auditor').val("");
    5. //必须重新渲染
    6. form.render('select');
    7. //弹出对话框
    8. layer.open({
    9. type: 1, //layer提供了5种层类型。可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
    10. title:'会议送审',
    11. area: ['426px', '140px'], //宽高
    12. skin: 'layui-layer-rim', //样式类名
    13. content: $('#audit'), //弹出内容。可以传入普通的html内容,还可以指定DOM,更可以随着type的不同而不同
    14. });
    15. }

     运行效果:

     

  • 相关阅读:
    彻底搞懂原生事件流和 React 事件流
    快速入门 Docker,看这一篇文章就够
    云呐|机房监控服务平台,机房监控服务平台有哪些
    Windows10 Docker 安装教程
    GPTS应用怎么创建?GPTS无法创建应用很卡怎么办
    我为什么拒绝了一个5年测开经验的候选人
    中华环保联合会获得国家“绿色制造体系” 第三方评价机构资格
    LeetCode每日一题——672. 灯泡开关 Ⅱ
    Langchain-Chatchat项目:1-整体介绍
    java八股文面试[数据库]——MySQL中事务的特性
  • 原文地址:https://blog.csdn.net/m0_67477525/article/details/125981113