【需求】:使用 fullcalendar日歷插件,完成如下功能:可以進行拖動,點擊空白處添加,雙擊后修改和刪除等功能。API 鏈接
一、html 文件中引入相關依賴,主要包括引入的 css和 js;

1 <!DOCTYPE html> 2 <html lang="zh_CN" xmlns:th="http://www.thymeleaf.org" 3 xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> 4 <meta charset="utf-8"> 5 <head th:include="include :: header"></head> 6 <body class="gray-bg"> 7 <div class="wrapper wrapper-content "> 8 <div class="col-sm-12"> 9 <div class="ibox"> 10 <div class="ibox-body"> 11 <div class="fixed-table-toolbar"> 12 <div class="columns pull-left col-md-2 nopadding"> 13 <input id="orgCode2" name="orgCode2" th:value="${orgCode2}" type="hidden"> 14 <select id="filter_orgCode" name="filter_orgCode" class="form-control" type="text" required="true"> 15 <option> </option> 16 </select> 17 <div class="error-msg"></div> 18 </div> 19 20 <div class="columns pull-left"> 21 <button class="btn btn-success" type="button" class="btn btn-primary" onclick="reloadCalendar()" id="btnSearch"> 22 <i aria-hidden="true"></i>查詢 23 </button> 24 <button shiro:hasPermission="centerInfo:personSchedul:add" type="button" class="btn btn-primary" onclick="add()"> 25 <i class="fa fa-plus" aria-hidden="true"></i>添加排班 26 </button> 27 <!--<button shiro:hasPermission="centerInfo:personSchedul:batchRemove" type="button" class="btn btn-danger" 28 onclick="batchRemove()"> 29 <i class="fa fa-trash" aria-hidden="true"></i>批量刪除 30 </button>--> 31 </div> 32 <div class="columns pull-left"> 33 <span style="font-size: 9px;">說明:點擊單元格空白處,可添加排班;雙擊單條排班可編輯和刪除</span> 34 </div> 35 </div> 36 <div id="senscloud-container" class="form-group table-contain senscloud-container" 37 style="border-top: solid 1px #EDEEF2;"> 38 <div style="padding: 10px 0;"> 39 <div id='calendar' class="col-xs-12"></div> 40 </div> 41 </div> 42 </div> 43 </div> 44 </div> 45 </div> 46 <!--shiro控制bootstraptable行內按鈕看見性 來自bootdo的創新方案 --> 47 <div> 48 <script type="text/javascript"> 49 var s_edit_h = 'hidden'; 50 var s_remove_h = 'hidden'; 51 var s_resetPwd_h = 'hidden'; 52 </script> 53 </div> 54 <div shiro:hasPermission="centerInfo:personSchedul:edit"> 55 <script type="text/javascript"> 56 s_edit_h = ''; 57 </script> 58 </div> 59 <div shiro:hasPermission="centerInfo:personSchedul:remove"> 60 <script type="text/javascript"> 61 var s_remove_h = ''; 62 </script> 63 </div> 64 <div shiro:hasPermission="centerInfo:personSchedul:resetPwd"> 65 <script type="text/javascript"> 66 var s_resetPwd_h = ''; 67 </script> 68 </div> 69 </div> 70 <div th:include="include :: footer"></div> 71 <link th:href="@{/css/plugins/fullcalendar/fullcalendar.css}" rel='stylesheet'/> 72 <link th:href="@{/css/plugins/fullcalendar/fullcalendar.print.css}" rel='stylesheet' media='print'/> 73 <link th:href="@{/css/bootstrap.min.css}" rel='stylesheet' type="text/css"/> 74 <script type="text/javascript" th:src="@{/js/plugins/jquery-ui/jquery-ui.min.js}"></script> 75 76 <script type="text/javascript" th:src="@{/js/plugins/fullcalendar/moment.min.js}"></script> 77 <script type="text/javascript" th:src="@{/js/plugins/fullcalendar/fullcalendar.min.js}"></script> 78 79 <link th:href="@{/css/plugins/bootstrap-timepicker/bootstrap-timepicker.min.css}" rel='stylesheet'/> 80 <script type="text/javascript" th:src="@{/js/plugins/bootstrap-timepicker/bootstrap-timepicker.min.js}"></script> 81 <script type="text/javascript" th:src="@{/js/plugins/datapicker/bootstrap-datepicker.js}"></script> 82 <script type="text/javascript" th:src="@{/js/appjs/centerInfo/perSchedul/personSchedul.js}"></script> 83 </body> 84 </html>
二、js 中使用 fullCalendar 插件完成該功能

1 var prefix = "/dms/centerInfo/personSchedul" 2 /** 3 * 在頁面加載此js文件 4 * 使用例:new Date().format("yyyy-MM-dd hh:mm:ss") 5 */ 6 Date.prototype.format = function (fmt) { 7 var o = { 8 "M+": this.getMonth() + 1, //月份 9 "d+": this.getDate(), //日 10 "h+": this.getHours(), //小時 11 "m+": this.getMinutes(), //分 12 "s+": this.getSeconds(), //秒 13 "q+": Math.floor((this.getMonth() + 3) / 3), //季度 14 "S": this.getMilliseconds() //毫秒 15 }; 16 if (/(y+)/.test(fmt)) { 17 fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 18 } 19 for (var k in o) { 20 if (new RegExp("(" + k + ")").test(fmt)) { 21 fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 22 } 23 } 24 return fmt; 25 } 26 27 var myCalendar; 28 var nextWeek = new Date(); 29 var tomorrow = new Date(); 30 nextWeek.setDate(nextWeek.getDate() + 7); 31 tomorrow.setDate(tomorrow.getDate() + 1); 32 33 var tomorrowWord = tomorrow.format('yyyy-MM-dd'); 34 var nextWeekWord = nextWeek.format('yyyy-MM-dd'); 35 $(function() { 36 37 //下拉框 orgcode 賦值 38 $("#filter_orgCode").select2({ 39 data:getOrgCode(), 40 placeholder:"請選擇", 41 allowClear:true, 42 language:"zh-CN" 43 }).val($("#orgCode2").val()).trigger("change"); 44 45 //如果分撥編碼為空,說明是超級管理員,可以進行下拉選擇,否則不允許修改 46 if($("#filter_orgCode").val() != null && $("#filter_orgCode").val() != ""){ 47 $("#filter_orgCode").attr("disabled",true); 48 } 49 50 //查詢條件進行復制 51 $('.timepicker').timepicker({ 52 defaultTime: '9:00', 53 showMeridian: false, 54 minuteStep: 1 55 }); 56 myCalendar = $("#calendar").fullCalendar({ 57 header: { 58 left: '', 59 center: 'title', 60 right: 'today prev,next' 61 }, 62 height: window.parent.document.body.clientHeight - 180, 63 windowResize: function (view) { 64 $('#calendar').fullCalendar('option', 'height', window.parent.document.body.clientHeight - 180); 65 }, 66 fixedWeekCount: false, 67 locale: getNowLanguage(1).toLowerCase(), 68 //設置是否可被單擊或者拖動選擇 69 selectable: true, 70 //點擊或者拖動選擇時,是否顯示時間范圍的提示信息,該屬性只在agenda視圖里可用 71 selectHelper: true, 72 //點擊或者拖動選中之后,點擊日歷外的空白區域是否取消選中狀態 true為取消 false為不取消,只有重新選擇時才會取消 73 unselectAuto: true, 74 events: function (start, end, callback) { 75 var submitGroup = $("#filter_orgCode").val().toString(); 76 if (myCalendar != null && myCalendar != undefined) { 77 serachCalendarWorkSchedule(submitGroup, start, end, callback); 78 } 79 }, 80 eventClick: function (event) { 81 //當點擊日歷中的某一日程(事件)時,觸發此操作,編輯人員排版 82 //edit(event.id) 83 }, 84 dayClick: function (date, allDay, jsEvent, view) { 85 //當單擊日歷中的某一天時,觸發callback,添加人員排版 86 add(date); 87 }, 88 //Event是否可被拖動或者拖拽 89 editable: true, 90 //Event被拖動時的不透明度 91 dragOpacity: 0.6, 92 eventDrop: function (event, dayDelta, minuteDelta, allDay, revertFunc) {//當拖拽完成並且時間改變時觸發 93 var color = event.backgroundColor; 94 if(color=='#E0FFFF'){ 95 layer.alert("已過期排班不能拖動!", {skin:'layui-layer-red',closeBtn:0,icon:2}); 96 revertFunc(); //恢復原狀 97 return; 98 } 99 $.ajax({ 100 type : 'POST', 101 url: prefix+"/dropView", 102 data: { 103 "dayDelta": dayDelta, 104 "id": event.id 105 }, 106 dataType: "json", 107 success: function (data) { 108 reloadCalendar(); 109 } 110 }); 111 }, 112 eventRender: function (event, element) { 113 //alert("eventRender") 114 }, 115 eventAfterRender: function (event, element, view) { 116 $(element).on("dblclick", function () { 117 //雙擊觸發該事件 118 edit(event.id); 119 }); 120 }, 121 eventResize: function (event, dayDelta, revertFunc) { 122 //alert("eventResize") 123 }, 124 }); 125 126 $("#beginDay").datepicker({ 127 format: 'yyyy-mm-dd',//顯示格式 128 todayHighlight: 1,//今天高亮 129 autoclose: 1,//選擇后自動關閉 130 minView: 1, 131 language: getNowLanguage(1) 132 }); 133 $("#endDay").datepicker({ 134 format: 'yyyy-mm-dd',//顯示格式 135 todayHighlight: 1,//今天高亮 136 autoclose: 1,//選擇后自動關閉 137 minView: 1, 138 language: getNowLanguage(1) 139 }); 140 141 $("#beginDay").val(tomorrowWord); 142 $("#endDay").val(nextWeekWord); 143 144 $(document).keyup(function (event) {//回車查詢 145 if (event.keyCode == 13) { 146 $("#btnSearch").trigger("click"); 147 } 148 }); 149 }); 150 151 //重新加載日歷中的信息 152 reloadCalendar = function () { 153 myCalendar.fullCalendar('refetchEvents'); 154 } 155 156 //添加員工排班 157 function add(date) { 158 layer.open({ 159 type : 2, 160 title : '添加排班', 161 maxmin : true, 162 shadeClose : false, // 點擊遮罩關閉層 163 area : [ '800px', '520px' ], 164 content : prefix + '/add' +"?date=" + date // iframe的url 165 }); 166 } 167 168 //批量刪除 169 function batchRemove() { 170 var rows = $('#exampleTable').bootstrapTable('getSelections'); // 返回所有選擇的行,當沒有選擇的記錄時,返回一個空數組 171 if (rows.length == 0) { 172 layer.msg("請選擇要刪除的數據"); 173 return; 174 } 175 layer.confirm("確認要刪除選中的'" + rows.length + "'條數據嗎?", { 176 btn : [ '確定', '取消' ] 177 // 按鈕 178 }, function() { 179 var ids = new Array(); 180 // 遍歷所有選擇的行數據,取每條數據對應的ID 181 $.each(rows, function(i, row) { 182 ids[i] = row['id']; 183 }); 184 $.ajax({ 185 type : 'POST', 186 data : { 187 "ids" : ids 188 }, 189 url : prefix + '/batchRemove', 190 success : function(r) { 191 if (r.code == 0) { 192 layer.msg(r.msg); 193 reLoad(); 194 } else { 195 layer.msg(r.msg); 196 } 197 } 198 }); 199 }, function() { 200 201 }); 202 } 203 204 //將數據庫的時間戳轉成 *年*月*日 字符串 205 function getDate(DBTime){ 206 var date = new Date(DBTime); 207 var year = date.getFullYear(); 208 var month = date.getMonth()+1; 209 var day = date.getDate(); 210 var dateStr; 211 if(month<10&&day<10){ 212 dateStr = year+"-0"+month+"-0"+day; 213 }else if(month<10&&day>=10){ 214 dateStr = year+"-0"+month+"-"+day; 215 }else if(month>=10&&day<10){ 216 dateStr = year+"-"+month+"-0"+day; 217 }else if(month>=10&&day>=10){ 218 dateStr = year+"-"+month+"-"+day; 219 } 220 return dateStr; 221 } 222 223 //將數據庫的時間戳轉成 *時*分 字符串 224 function getTime(DBTime){ 225 var time = DBTime.substring(0,2)+"-"+DBTime.substring(3,5); 226 return time; 227 } 228 229 /** 230 * 獲取當前語言類型 231 * @return {*} 232 */ 233 function getNowLanguage(type) { 234 try { 235 var rk = $.cookie('resource_key'); 236 if (!rk) { 237 rk = "zh_CN"; 238 } 239 if (type) { 240 // 日期控件 241 if ("1" == type) { 242 if ("en_US" == rk) { 243 return "en"; 244 } 245 if ("zh_CN" == rk) { 246 return "zh-CN"; 247 } 248 // 評分控件 249 } else if ("2" == type) { 250 if ("en_US" == rk) { 251 return "en"; 252 } 253 if ("zh_CN" == rk) { 254 return "zh"; 255 } 256 } 257 } 258 return rk; 259 } catch (e) { 260 return "en_US"; 261 } 262 } 263 264 //查詢,按用戶組織查詢排班 265 serachCalendarWorkSchedule = function (addGroup, start, end, callback) { 266 var groupIds = ""; 267 if (addGroup != null && addGroup != '' && addGroup != 'undefined') { 268 groupIds = addGroup; 269 } else { 270 groupIds = $("#filter_orgCode").val().toString(); 271 272 } 273 myCalendar.fullCalendar('removeEvents'); 274 var startDate = start; 275 if (undefined == startDate || null == startDate || "" == startDate) { 276 startDate = myCalendar.fullCalendar('getView').start.valueOf(); 277 } 278 var endDate = end; 279 if (undefined == endDate || null == endDate || "" == endDate) { 280 endDate = myCalendar.fullCalendar('getView').end.valueOf(); 281 } 282 283 if (groupIds == null || groupIds == undefined || groupIds == "" || groupIds == "null") { 284 return; 285 } 286 287 $.ajax({ 288 type: "POST", 289 url: prefix + "/list", 290 data: { 291 "start": TimeStampConvertDate(startDate), 292 "end": TimeStampConvertDate(endDate), 293 "orgCode": groupIds 294 }, 295 async: false, 296 dataType: "json", 297 success: function (data) { 298 var dataList = []; 299 var jsonData = data; 300 for (var i = 0; i < jsonData.length; i++) { 301 var begin_time = DataTimeConvertDate(jsonData[i].startTime); 302 var ccDate = begin_time.replace(/\-/g,""); 303 var nowDate = new Date().format("yyyyMMdd"); 304 if( ccDate > nowDate ){ 305 data = { 306 id: jsonData[i].id, 307 title: timestampToHourMinute(jsonData[i].startTime) + "-" + timestampToHourMinute(jsonData[i].endTime) + ":【" + jsonData[i].staffName + "】" + "分撥:"+ jsonData[i].orgCode, 308 start: begin_time, 309 allday: true, 310 backgroundColor: '#FFFFE0',//大於今天的設置 311 borderColor:'black' 312 }; 313 }else if (ccDate == nowDate){ 314 data = { 315 id: jsonData[i].id, 316 title: timestampToHourMinute(jsonData[i].startTime) + "-" + timestampToHourMinute(jsonData[i].endTime) + ":【" + jsonData[i].staffName + "】" + "分撥:"+ jsonData[i].orgCode, 317 start: begin_time, 318 allday: true, 319 backgroundColor: '#98FB98',//當天的設置 320 borderColor:'black', 321 }; 322 }else{ 323 data = { 324 id: jsonData[i].id, 325 title: timestampToHourMinute(jsonData[i].startTime) + "-" + timestampToHourMinute(jsonData[i].endTime) + ":【" + jsonData[i].staffName + "】" + "分撥:"+ jsonData[i].orgCode, 326 start: begin_time, 327 allday: true, 328 backgroundColor: '#E0FFFF',//過期的設置 329 borderColor:'black' 330 }; 331 } 332 dataList.push(data); 333 } 334 //反饋,重新賦值event的值,進行綁定 335 callback(dataList); 336 } 337 }); 338 } 339 340 //日期截取 341 function DataTimeConvertDate(timeStamp) { 342 var newDate = new Date(timeStamp); 343 return newDate.format('yyyy-MM-dd'); 344 } 345 346 //時間戳轉成時間格式(帶跨時區差值處理) 347 function TimeStampConvertDate(timeStamp) { 348 var timestamp3; 349 if(typeof(timeStamp) == "number") 350 timestamp3 = convertTimestampCompensate(timeStamp); 351 else 352 timestamp3 = timeStamp; 353 354 var newDate = new Date(); 355 newDate.setTime(timestamp3); 356 return newDate.format('yyyy-MM-dd'); 357 } 358 359 //找到小時和分鍾 360 function timestampToHourMinute(timestamp) { 361 var date = new Date(timestamp);//時間戳為10位需*1000,時間戳為13位的話不需乘1000 362 h = date.getHours() + ':'; 363 m = date.getMinutes(); 364 if (m < 10) { 365 m = "0" + m; 366 } 367 return h + m; 368 } 369 370 /** 371 * timestamp型轉date型前的時區補差 372 * @param dateTime 373 * @returns {string|*} 374 */ 375 function convertTimestampCompensate(timestamp) { 376 if (!timestamp) 377 return null; 378 379 const serverTimeZone = getServerTimeZone(); 380 if(!serverTimeZone) 381 return timestamp; 382 383 // 當前時區與中時區時差,以min為維度 384 const _dif = new Date().getTimezoneOffset(); 385 // 計算當前時區時間: 當前時區時間 = 服務器時區時間 + 服務器時區 - 當前時區 386 const localDateTime = timestamp + serverTimeZone * 60 * 60 * 1000 - (-_dif * 60 * 1000); 387 return localDateTime; 388 } 389 390 function edit(id) { 391 layer.open({ 392 type : 2, 393 title : '編輯排班', 394 maxmin : true, 395 shadeClose : false, // 點擊遮罩關閉層 396 area : [ '800px', '520px' ], 397 content : prefix + '/edit/' + id // iframe的url 398 }); 399 } 400 401 /** 獲取 orgCode 下拉列表 402 * @Description 403 * @Author zhengzhaoxiang 404 * @Date 2020/8/24 8:58 405 * @Param 406 * @Return 407 */ 408 function getOrgCode() { 409 var orgCode = ""; 410 $.ajax({ 411 type: "POST", 412 async: false, 413 url: "/dms/common/baseInfo/selectCenter", 414 data: "", 415 dataType: "json", 416 contentType: "application/json", 417 success: function (data) { 418 if (data) { 419 orgCode = data; 420 } 421 } 422 }) 423 return orgCode; 424 }
三、controller 層實現代碼展示

1 import cn.hutool.core.util.StrUtil; 2 import org.apache.commons.beanutils.BeanMap; 3 import org.apache.shiro.authz.annotation.RequiresPermissions; 4 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.stereotype.Controller; 6 import org.springframework.ui.Model; 7 import org.springframework.web.bind.annotation.*; 8 9 import javax.servlet.http.HttpServletRequest; 10 import java.sql.Timestamp; 11 import java.util.*; 12 13 /** 14 * 人員排班 15 * @author zzx 16 * @email zhengzhaojava@163.com 17 * @date 2020-08-18 13:32:22 18 */ 19 20 @Controller 21 @RequestMapping("/centerInfo/personSchedul") 22 public class PersonSchedulController extends BaseController { 23 @Autowired 24 private PersonSchedulService personSchedulService; 25 /** 26 * @Description 頁面初始化功能 27 * @Author zhengzhaoxiang 28 * @Date 2020/8/24 15:03 29 * @Param [model] 30 * @Return java.lang.String 31 */ 32 @GetMapping() 33 @RequiresPermissions("centerInfo:personSchedul:personSchedul") 34 String PersonSchedul(Model model){ 35 model.addAttribute("orgCode2",getOrgCode()); 36 return "centerInfo/perSchedul/personSchedul"; 37 } 38 39 @ResponseBody 40 @PostMapping("/list") 41 public List list(@RequestParam Map<String, Object> params){ 42 //查詢列表數據 43 List<PersonSchedulDO> personSchedulList = personSchedulService.list(params); 44 return personSchedulList; 45 } 46 47 /** 48 * @Description 添加頁面 49 * @Author zhengzhaoxiang 50 * @Date 2020/8/24 15:00 51 * @Param [model] 52 * @Return java.lang.String 53 */ 54 @GetMapping("/add") 55 String add(HttpServletRequest request,Model model){ 56 String currDate = request.getParameter("date"); 57 //當前日期 58 model.addAttribute("currDate",currDate); 59 model.addAttribute("orgCode",getOrgCode()); 60 return "centerInfo/perSchedul/add"; 61 } 62 63 /** 64 * @Description 修改頁面,同時返回 回顯信息。 65 * @Author zhengzhaoxiang 66 * @Date 2020/8/24 15:01 67 * @Param [id, model] 68 * @Return java.lang.String 69 */ 70 @GetMapping("/edit/{id}") 71 String edit(@PathVariable("id") Integer id,Model model){ 72 PersonSchedulDO personSchedul = personSchedulService.get(id); 73 Map<String, Object> personSchedulMap = new HashMap<>(); 74 Map map = new BeanMap(personSchedul); 75 personSchedulMap.putAll(map); 76 Date startTime = personSchedul.getStartTime(); 77 String times = DateUtils.formatDate(startTime, DateUtils.DATE_TIME_PATTERN); 78 //修改頁面的日期和時間是分開存儲的 79 if(StrUtil.isNotBlank(times)){ 80 String[] time = times.split(" "); 81 personSchedulMap.put("beginDay",time[0]); 82 personSchedulMap.put("beginTime",time[1].substring(0,5)); 83 } 84 Date endTime = personSchedul.getEndTime(); 85 String endTimes = DateUtils.formatDate(endTime, DateUtils.DATE_TIME_PATTERN); 86 if(StrUtil.isNotBlank(endTimes)){ 87 String[] time = endTimes.split(" "); 88 personSchedulMap.put("endDay",time[0]); 89 personSchedulMap.put("endTime",time[1].substring(0,5)); 90 } 91 model.addAttribute("personSchedul", personSchedulMap); 92 return "centerInfo/perSchedul/edit"; 93 } 94 95 /** 96 * @Description 保存, 需求修改:為了方便后期單個任務的修改,這里將 開始時間 與 結束時間 區間進行拆分,每一個時間存儲一個單獨的任務,方便后期其他處理 97 * @Author zhengzhaoxiang 98 * @Date 2020/8/24 15:00 99 * @Param 100 * @Return 101 */ 102 @ResponseBody 103 @PostMapping("/save") 104 @RequiresPermissions("centerInfo:personSchedul:add") 105 public R save(HttpServletRequest request){ 106 //獲取所屬分撥中心 107 String orgCode = request.getParameter("orgCode"); 108 //獲取員工姓名 109 String staffName = request.getParameter("staffName"); 110 //開始日期 111 String beginDay = request.getParameter("beginDay"); 112 //結束日期 113 String endDay = request.getParameter("endDay"); 114 //工作時間 115 String beginTime = request.getParameter("beginTime"); 116 //工作時間 117 String endTime = request.getParameter("endTime"); 118 //數據校驗 119 R x = checkSaveAndUpdate(staffName, beginDay, endDay, beginTime, endTime,orgCode); 120 if (x != null) return x; 121 //備注 122 String remark = request.getParameter("remark"); 123 //組裝數據 124 PersonSchedulDO personSchedulDO = getPersonSchedulDO(orgCode, staffName, beginDay, beginDay, beginTime, endTime, remark); 125 /** 126 * 組裝保存的對象:根據 startDay 與 endDay 進行循環插入多條 127 */ 128 int start = Integer.valueOf(beginDay.replace("-", "")); 129 int end = Integer.valueOf(endDay.replace("-", "")); 130 //開始時間 131 String startTimeString = personSchedulDO.getStartTime().toString(); 132 //結束時間 133 String endTimeString = personSchedulDO.getEndTime().toString(); 134 for(int i=start; i<= end; i++){ 135 //開始時間 136 String dateAfterDays = DateUtils.getDateAfterNDays(startTimeString, i-start); 137 //結束時間 138 String dateEndDays = DateUtils.getDateAfterNDays(endTimeString, i-start); 139 //修改組裝數據的 startTime 和 endTime 140 personSchedulDO.setStartTime(DateUtils.getDateFromString(dateAfterDays,DateUtils.DATE_FORMAT_DATETIME)); 141 personSchedulDO.setEndTime(DateUtils.getDateFromString(dateEndDays,DateUtils.DATE_FORMAT_DATETIME)); 142 //入庫 143 personSchedulService.save(personSchedulDO); 144 } 145 return R.ok(); 146 } 147 148 /** 149 * @Description 增加修改時,數據封裝 150 * @Author zhengzhaoxiang 151 * @Date 2020/8/24 15:05 152 * @Param [orgCode, staffName, beginDay, endDay, beginTime, endTime, remark] 153 * @Return com.yunda.base.centerInfo.domain.PersonSchedulDO 154 */ 155 private PersonSchedulDO getPersonSchedulDO(String orgCode, String staffName, String beginDay, String endDay, String beginTime, String endTime, String remark) { 156 //創建需要進行存庫的對象 157 PersonSchedulDO personSchedulDO = new PersonSchedulDO(); 158 personSchedulDO.setOrgCode(orgCode); 159 personSchedulDO.setStaffName(staffName); 160 personSchedulDO.setRemark(remark); 161 //組裝時間 162 String newBegintime = beginDay + " " + beginTime + ":00"; 163 String newEndtime = endDay + " " + endTime + ":00"; 164 165 personSchedulDO.setStartTime(Timestamp.valueOf(newBegintime)); 166 personSchedulDO.setEndTime(Timestamp.valueOf(newEndtime)); 167 return personSchedulDO; 168 } 169 170 /** 171 * @Description 修改 172 * @Author zhengzhaoxiang 173 * @Date 2020/8/24 15:02 174 * @Param 175 * @Return 176 */ 177 @ResponseBody 178 @RequestMapping("/update") 179 @RequiresPermissions("centerInfo:personSchedul:edit") 180 public R update( HttpServletRequest request){ 181 //獲取用戶ID 182 String id = request.getParameter("id"); 183 if(StrUtil.isBlank(id)){ 184 return R.error("id不能為空"); 185 } 186 //獲取所屬分撥中心 187 String orgCode = request.getParameter("orgCode"); 188 //獲取員工姓名 189 String staffName = request.getParameter("staffName"); 190 //工作日期 191 String beginDay = request.getParameter("beginDay"); 192 //工作時間 193 String beginTime = request.getParameter("beginTime"); 194 //工作時間 195 String endTime = request.getParameter("endTime"); 196 //數據校驗 197 R x = checkSaveAndUpdate(staffName, beginDay, beginDay, beginTime, endTime,orgCode); 198 if (x != null) return x; 199 //備注 200 String remark = request.getParameter("remark"); 201 //組裝保存的對象 202 PersonSchedulDO personSchedulDO = getPersonSchedulDO(orgCode, staffName, beginDay, beginDay, beginTime, endTime, remark); 203 personSchedulDO.setId(Integer.valueOf(id)); 204 personSchedulService.update(personSchedulDO); 205 return R.ok(); 206 } 207 208 /** 209 * @Description 刪除 210 * @Author zhengzhaoxiang 211 * @Date 2020/8/24 15:02 212 * @Param 213 * @Return 214 */ 215 @PostMapping( "/remove") 216 @ResponseBody 217 public R remove( String id){ 218 if(StrUtil.isNotBlank(id) && personSchedulService.remove(Integer.valueOf(id))>0){ 219 return R.ok(); 220 } 221 return R.error(); 222 } 223 224 /** 225 * @Description 批量刪除 226 * @Author zhengzhaoxiang 227 * @Date 2020/8/24 15:03 228 * @Param 229 * @Return 230 */ 231 @PostMapping( "/batchRemove") 232 @ResponseBody 233 @RequiresPermissions("centerInfo:personSchedul:batchRemove") 234 public R remove(@RequestParam("ids[]") Integer[] ids){ 235 personSchedulService.batchRemove(ids); 236 return R.ok(); 237 } 238 239 240 /** 241 * @Description 拖動任務時,進行時間上的處理 242 * @Author zhengzhaoxiang 243 * @Date 2020/8/24 15:04 244 * @Param [request] 245 * @Return com.yunda.base.common.utils.R 246 */ 247 @PostMapping("/dropView") 248 @ResponseBody 249 public R dropView(HttpServletRequest request){ 250 String id = request.getParameter("id"); 251 if(StrUtil.isBlank(id)){ 252 return R.error("id 不能為空"); 253 } 254 String dayDelta = request.getParameter("dayDelta"); 255 if(StrUtil.isBlank(dayDelta)){ 256 return R.error("dayDelta"); 257 } 258 //拖動日期進行計算 259 PersonSchedulDO personSchedulDO = personSchedulService.get(Integer.valueOf(id)); 260 Date startTime = personSchedulDO.getStartTime(); 261 String dateTime = DateUtils.formatDate(startTime, DateUtils.DATE_TIME_PATTERN); 262 String dateAfterNDays = DateUtils.getDateAfterNDays(dateTime, Integer.valueOf(dayDelta)); 263 //日期 264 Date dateFromString = DateUtils.getDateFromString(dateAfterNDays, DateUtils.DATE_TIME_PATTERN); 265 personSchedulDO.setStartTime(dateFromString); 266 //根據ID進行更新 267 personSchedulService.update(personSchedulDO); 268 return R.ok(); 269 } 270 }
四、表結構展示

1 SET NAMES utf8mb4; 2 SET FOREIGN_KEY_CHECKS = 0; 3 4 -- ---------------------------- 5 -- Table structure for person_schedul 6 -- ---------------------------- 7 DROP TABLE IF EXISTS `person_schedul`; 8 CREATE TABLE `person_schedul` ( 9 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵', 10 `org_code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '所屬分撥中心', 11 `staff_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '員工姓名', 12 `start_time` datetime(0) NULL DEFAULT NULL COMMENT '開始日期', 13 `end_time` datetime(0) NULL DEFAULT NULL COMMENT '結束日期', 14 `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '備注', 15 PRIMARY KEY (`id`) USING BTREE 16 ) ENGINE = InnoDB AUTO_INCREMENT = 150 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '人員排班' ROW_FORMAT = Compact; 17 18 SET FOREIGN_KEY_CHECKS = 1;
五、add 頁面展示,edit 與之類似,需要添加 th:value="${personSchedul.endTime}" 等進行回顯。

1 <!DOCTYPE html> 2 <html lang="zh_CN" xmlns:th="http://www.thymeleaf.org"> 3 <meta charset="utf-8"> 4 <head th:include="include :: header"></head> 5 <body class="gray-bg"> 6 <div class="wrapper wrapper-content "> 7 <div class="row"> 8 <div class="col-sm-12"> 9 <div class="ibox float-e-margins"> 10 <div class="ibox-content"> 11 <form class="form-horizontal m-t" id="signupForm"> 12 <input id="currDate" name="currDate" th:value="${currDate}" type="hidden"> 13 <div class="form-group"> 14 <label class="col-sm-3 control-label">所屬分撥中心:</label> 15 <div class="col-sm-8"> 16 <input id="orgCode" name="orgCode" class="form-control" th:value="${orgCode}" type="text" readonly="true" required="true"> 17 </div> 18 </div> 19 <div class="form-group"> 20 <label class="col-sm-3 control-label">員工姓名:</label> 21 <div class="col-sm-8"> 22 <select id="staffName" name="staffName" class="form-control" type="text" required="true"> 23 <option> </option> 24 </select> 25 <div class="error-msg"></div> 26 </div> 27 </div> 28 <div class="form-group"> 29 <label class="col-sm-3 control-label">開始日期:</label> 30 <div class="col-sm-8"> 31 <input id="beginDay" name="beginDay" class="form-control" type="date"> 32 </div> 33 </div> 34 <div class="form-group"> 35 <label class="col-sm-3 control-label">結束日期:</label> 36 <div class="col-sm-8"> 37 <input id="endDay" name="endDay" class="form-control" type="date"> 38 </div> 39 </div> 40 <div class="form-group"> 41 <label class="col-sm-3 control-label">工作時間:</label> 42 <div class="col-sm-2" style="position: relative; float: left; padding-left: 19px;" 43 align="left"> 44 <div class="input-group monday"> 45 <input type="time" id="beginTime" name="beginTime" 46 class="form-control timepicker timepicker-default startTime" autocomplete="off"> 47 </div> 48 </div> 49 <div style="width: 3px; position: relative; float: left;" align="center"> 50 <p>-</p> 51 </div> 52 <div class="col-sm-2" style="position: relative; float: left;" align="left"> 53 <div class="input-group monday"> 54 <input type="time" id="endTime" name="endTime" 55 class="form-control timepicker timepicker-default endTime" autocomplete="off"> 56 </div> 57 </div> 58 </div> 59 <div class="form-group"> 60 <label class="col-sm-3 control-label">備注:</label> 61 <div class="col-sm-8"> 62 <input id="remark" name="remark" class="form-control" type="text" maxlength="100"> 63 </div> 64 </div> 65 <div class="form-group"> 66 <div class="col-sm-8 col-sm-offset-3"> 67 <button type="submit" class="btn btn-primary">提交</button> 68 </div> 69 </div> 70 </form> 71 </div> 72 </div> 73 </div> 74 </div> 75 </div> 76 <div th:include="include::footer"></div> 77 <script type="text/javascript" th:src="@{/js/appjs/centerInfo/perSchedul/add.js}"> 78 </script> 79 </body> 80 </html>
六、add.js 代碼展示

1 $().ready(function() { 2 validateRule(); 3 $("#staffName").select2({ 4 data:getStaffName(), 5 placeholder:"請選擇", 6 allowClear:true, 7 language:"zh-CN" 8 }).val(null).trigger("change"); 9 }); 10 11 $.validator.setDefaults({ 12 submitHandler : function() { 13 save(); 14 } 15 }); 16 function save() { 17 $.ajax({ 18 cache : true, 19 type : "POST", 20 url : "/dms/centerInfo/personSchedul/save", 21 data : $('#signupForm').serialize(),// 你的formid 22 async : false, 23 error : function(request) { 24 parent.layer.alert("Connection error"); 25 }, 26 success : function(data) { 27 if (data.code == 0) { 28 parent.layer.msg("操作成功"); 29 parent.reloadCalendar(); 30 var index = parent.layer.getFrameIndex(window.name); // 獲取窗口索引 31 parent.layer.close(index); 32 33 } else { 34 parent.layer.alert(data.msg) 35 } 36 37 } 38 }); 39 40 } 41 42 /** 43 * 在頁面加載此js文件 44 * 使用例:new Date().format("yyyy-MM-dd hh:mm:ss") 45 */ 46 Date.prototype.format = function (fmt) { 47 var o = { 48 "M+": this.getMonth() + 1, //月份 49 "d+": this.getDate(), //日 50 "h+": this.getHours(), //小時 51 "m+": this.getMinutes(), //分 52 "s+": this.getSeconds(), //秒 53 "q+": Math.floor((this.getMonth() + 3) / 3), //季度 54 "S": this.getMilliseconds() //毫秒 55 }; 56 if (/(y+)/.test(fmt)) { 57 fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 58 } 59 for (var k in o) { 60 if (new RegExp("(" + k + ")").test(fmt)) { 61 fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 62 } 63 } 64 return fmt; 65 } 66 67 function validateRule() { 68 var icon = "<i class='fa fa-times-circle'></i> "; 69 $("#signupForm").validate({ 70 rules : { 71 name : { 72 required : true 73 } 74 }, 75 messages : { 76 name : { 77 required : icon + "請輸入姓名" 78 } 79 } 80 }) 81 //如果點擊頁面時,就根據頁面點擊的日期為准 82 var weekTime 83 if($('#currDate').val() != null && $('#currDate').val() != "" && $('#currDate').val() !="undefined"){ 84 weekTime = new Date($('#currDate').val()); 85 $("#beginDay").val(new Date($('#currDate').val()).format('yyyy-MM-dd')); 86 }else{ 87 $("#beginDay").val(new Date().format('yyyy-MM-dd')); 88 weekTime = new Date(); 89 } 90 weekTime.setDate(weekTime.getDate() + 7); 91 $("#endDay").val(weekTime.format('yyyy-MM-dd')); 92 $('#beginTime').val("09:00"); 93 $('#endTime').val("17:00"); 94 } 95 96 function getStaffName() { 97 $.ajax({ 98 type: "POST", 99 url: "/dms/centerInfo/personSchedul/getUserInfo", 100 data: '', 101 async: false, 102 dataType: "json", 103 // contentType : "application/json", 104 success: function (data) { 105 if (data) { 106 types = data; 107 } 108 } 109 }) 110 return types; 111 }
七、edit.js 代碼展示:刪除功能也在該頁面完成

1 var prefix = "/dms/centerInfo/personSchedul" 2 3 $().ready(function() { 4 validateRule(); 5 $("#staffName").select2({ 6 data:getStaffName(), 7 placeholder:"請選擇", 8 allowClear:true, 9 language:"zh-CN" 10 }).val($("#staffName2").val()).trigger("change"); 11 }); 12 13 $.validator.setDefaults({ 14 submitHandler : function() { 15 update(); 16 } 17 }); 18 function update() { 19 $.ajax({ 20 cache : true, 21 type : "POST", 22 url : "/dms/centerInfo/personSchedul/update", 23 data : $('#signupForm').serialize(),// 你的formid 24 async : false, 25 error : function(request) { 26 parent.layer.alert("Connection error"); 27 }, 28 success : function(data) { 29 if (data.code == 0) { 30 parent.layer.msg("操作成功"); 31 parent.reloadCalendar(); 32 var index = parent.layer.getFrameIndex(window.name); // 獲取窗口索引 33 parent.layer.close(index); 34 35 } else { 36 parent.layer.alert(data.msg) 37 } 38 39 } 40 }); 41 42 } 43 function validateRule() { 44 var icon = "<i class='fa fa-times-circle'></i> "; 45 $("#signupForm").validate({ 46 rules : { 47 name : { 48 required : true 49 } 50 }, 51 messages : { 52 name : { 53 required : icon + "請輸入名字" 54 } 55 } 56 }) 57 } 58 59 function getStaffName() { 60 $.ajax({ 61 type: "POST", 62 url: "/dms/centerInfo/personSchedul/getUserInfo", 63 data: '', 64 async: false, 65 dataType: "json", 66 // contentType : "application/json", 67 success: function (data) { 68 if (data) { 69 types = data; 70 } 71 } 72 }) 73 return types; 74 } 75 76 function remove() { 77 layer.confirm('確定要刪除選中的記錄?', { 78 btn : [ '確定', '取消' ] 79 }, function() { 80 $.ajax({ 81 url : prefix+"/remove", 82 type : "post", 83 data : { 84 'id' : $("#id").val() 85 }, 86 success : function(r) { 87 if (r.code==0) { 88 layer.msg(r.msg); 89 parent.reloadCalendar(); 90 var index = parent.layer.getFrameIndex(window.name); // 獲取窗口索引 91 parent.layer.close(index); 92 }else{ 93 parent.layer.msg(r.msg); 94 } 95 } 96 }); 97 }) 98 }