今天呢,我的头给我一个需求,就是让我做一个时间段是否重复的问题。刚开始打算自己写的,按照自己的思路来,什么时间段跨天了怎么验证是否重复都想了一下,没有想出来,没办法,百度了一下。原文链接在文章下面会给出。
一.需求背景
需求背景就是一个工厂的工人有休息的固定时间。一天休息的时间段有多个,但是这些时间段是不可以有交集。
二. 前端页面jsp
我们先来看一下效果图:
这个呢,就是维护rest表的页面图。休息时段名使用的是textbox,因为可以通过getText方法和setText轻松的得到这个文本框的值和设置文本框的文本值。
而日期框使用的是Wdate easyui-validatebox日期验证框。
直接贴一下jsp代码:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<%@ include file="../shared/head.jsp"%>
<script src="<%=request.getContextPath()%>/plugins/easyui-1.5.1/jquery.easyui.min.js"></script>
<script src="<%=request.getContextPath()%>/plugins/easyui-1.5.1/locale/easyui-lang-zh_CN.js"></script>
<script src="<%=request.getContextPath()%>/js/hyapp.js"></script>
<script src="<%=request.getContextPath()%>/js/hyapp.easyui-dialog.js"></script>
<script src="<%=request.getContextPath()%>/js/basic/restPeriod.js"></script>
<script type="text/javascript" src="<%=request.getContextPath()%>/plugins/My97DatePicker/WdatePicker.js"></script>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>休息时段管理</title>
</head>
<body class="easyui-layout" data-options="fit:true">
<!-- 用来显示数据 -->
<div data-options="region:'center',border:false" style="padding:2px;">
<div>
<a class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true" onclick="doAdd();" href="javascript:void(0);">添加</a>
<a class="easyui-linkbutton" data-options="iconCls:'icon-edit',plain:true" onclick="doEdit();" href="javascript:void(0)">编辑</a>
<a class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true" onclick="doRemove();" href="javascript:void(0)">删除</a>
</div>
<!-- 数据网格,用来显示数据 -->
<table id="dataGrid" class="easyui-datagrid" data-options="singleSelect:false,rownumbers:true,
fit:true,remoteSort:false,method:'get',pagination:true,pageSize:30,pageList:[30,100,500],
onLoadSuccess:handleLoadSuccess,onDblClickRow:handleDblClick">
<thead>
<tr>
<th data-options="field:'id',checkbox:true,width:100"></th>
<th data-options="field:'restName',width:200,halign:'center',align:'left'">休息时段名称</th>
<th data-options="field:'rest01Begin',width:200,halign:'center',align:'left'">休息时段1 开始时间</th>
<th data-options="field:'rest01End',width:200,halign:'center',align:'left'">休息时段1 结束时间</th>
<th data-options="field:'rest02Begin',width:200,halign:'center',align:'left'">休息时段2 开始时间</th>
<th data-options="field:'rest02End',width:200,halign:'center',align:'left'">休息时段2 结束时间</th>
<th data-options="field:'rest03Begin',width:200,halign:'center',align:'left'">休息时段3 开始时间</th>
<th data-options="field:'rest03End',width:200,halign:'center',align:'left'">休息时段3 结束时间</th>
<th data-options="field:'rest04Begin',width:200,halign:'center',align:'left'">休息时段4 开始时间</th>
<th data-options="field:'rest04End',width:200,halign:'center',align:'left'">休息时段4 结束时间</th>
<th data-options="field:'rest05Begin',width:200,halign:'center',align:'left'">休息时段5 开始时间</th>
<th data-options="field:'rest05End',width:200,halign:'center',align:'left'">休息时段5 结束时间</th>
<th data-options="field:'rest06Begin',width:200,halign:'center',align:'left'">休息时段6 开始时间</th>
<th data-options="field:'rest06End',width:200,halign:'center',align:'left'">休息时段6 结束时间</th>
<th data-options="field:'rest07Begin',width:200,halign:'center',align:'left'">休息时段7 开始时间</th>
<th data-options="field:'rest07End',width:200,halign:'center',align:'left'">休息时段7 结束时间</th>
<th data-options="field:'rest08Begin',width:200,halign:'center',align:'left'">休息时段8 开始时间</th>
<th data-options="field:'rest08End',width:200,halign:'center',align:'left'">休息时段8 结束时间</th>
<th data-options="field:'rest09End',width:200,halign:'center',align:'left'">休息时段9 开始时间</th>
<th data-options="field:'rest09Begin',width:200,halign:'center',align:'left'">休息时段9 结束时间</th>
<th data-options="field:'remark',width:200,halign:'center',align:'left'">备注</th>
</tr>
</thead>
</table>
</div>
<!-- 添加框 -->
<div id="addDialog" class="easyui-dialog" data-options="title:'增加或编辑',modal:true,closed:true,
buttons:'#dialog-buttons'" style="width:580px; height:400px;">
<form id="addForm" name="addForm">
<input id="id" name="id" type="hidden" value="" />
<table>
<tr>
<td> </td>
</tr>
<tr>
<td align="right" width="70"> </td>
<td align="right" width="80">休息时段名:</td>
<td>
<input id="restName" class="easyui-textbox" data-options="required:true" style="width:140px">
</td>
</tr>
<tr>
<td align="right" width="70">休息时段1</td>
<td align="right" width="80">开始时间:</td>
<td>
<input id="rest01Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
<td align="right" width="80">结束时间</td>
<td>
<input id="rest01End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
</tr>
<tr>
<td align="right" width="70">休息时段2</td>
<td align="right" width="80">开始时间:</td>
<td>
<input id="rest02Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
<td align="right" width="80">结束时间</td>
<td>
<input id="rest02End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
</tr>
<tr>
<td align="right" width="70">休息时段3</td>
<td align="right" width="80">开始时间:</td>
<td>
<input id="rest03Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
<td align="right" width="80">结束时间</td>
<td>
<input id="rest03End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
</tr>
<tr>
<td align="right" width="70">休息时段4</td>
<td align="right" width="80">开始时间:</td>
<td>
<input id="rest04Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
<td align="right" width="80">结束时间</td>
<td>
<input id="rest04End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
</tr>
<tr>
<td align="right" width="70">休息时段5</td>
<td align="right" width="80">开始时间:</td>
<td>
<input id="rest05Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
<td align="right" width="80">结束时间</td>
<td>
<input id="rest05End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
</tr>
<tr>
<td align="right" width="70">休息时段6</td>
<td align="right" width="80">开始时间:</td>
<td>
<input id="rest06Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
<td align="right" width="80">结束时间</td>
<td>
<input id="rest06End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
</tr>
<tr>
<td align="right" width="70">休息时段7</td>
<td align="right" width="80">开始时间:</td>
<td>
<input id="rest07Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
<td align="right" width="80">结束时间</td>
<td>
<input id="rest07End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
</tr>
<tr>
<td align="right" width="70">休息时段8</td>
<td align="right" width="80">开始时间:</td>
<td>
<input id="rest08Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
<td align="right" width="80">结束时间</td>
<td>
<input id="rest08End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
</tr>
<tr>
<td align="right" width="70">休息时段9</td>
<td align="right" width="80">开始时间:</td>
<td>
<input id="rest09Begin" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
<td align="right" width="80">结束时间</td>
<td>
<input id="rest09End" class="Wdate easyui-validatebox" style="width:140px;" onClick="WdatePicker({dateFmt:'HH:mm',readOnly:true})" />
</td>
</tr>
</table>
</form>
</div>
<!-- 按钮工具栏 -->
<div id="dialog-buttons">
<a href="javascript:void(0);" class="easyui-linkbutton" data-options="iconCls:'icon-ok'" onclick="executeAdd()">确定</a>
<a href="javascript:void(0);" class="easyui-linkbutton" data-options="iconCls:'icon-no'" onclick="javascript:$('#addDialog').dialog('close');">取消</a>
</div>
</body>
</html>
三.js代码
当然了,最终的实现肯定是要靠js代码了。
$(function() {
doSearch();
});
function doSearch() {
hyapp.ajaxPost(hyapp.getContextPath() + "/basic/restPeriod/getRestList", {},
function(result) {
$("#dataGrid").datagrid({
loadFilter: pagerFilter
}).datagrid("loadData", result);
},
function(xhr, status) {
hyapp.showError("错误", "加载失败!")
})
}
/**
* 相应添加
*/
function doAdd() {
$('#addForm').form('clear'); //清空表单中所有输入框中的值。
openAddDialog();
}
/**
* 打开添加对话框
*/
function openAddDialog() {
$("#addDialog").dialog("open");
}
/**
* 得到对话框的数据
*/
function getDialogData() {
var obj = {};
obj.id = $("#id").val();
obj.restName = $("#restName").textbox("getText");
obj.rest01Begin = $('#rest01Begin').val();
obj.rest01End = $('#rest01End').val();
obj.rest02Begin = $('#rest02Begin').val();
obj.rest02End = $('#rest02End').val();
obj.rest03Begin = $('#rest03Begin').val();
obj.rest03End = $('#rest03End').val();
obj.rest04Begin = $('#rest04Begin').val();
obj.rest04End = $('#rest04End').val();
obj.rest05Begin = $('#rest05Begin').val();
obj.rest05End = $('#rest05End').val();
obj.rest06Begin = $('#rest06Begin').val();
obj.rest06End = $('#rest06End').val();
obj.rest07Begin = $('#rest07Begin').val();
obj.rest07End = $('#rest07End').val();
obj.rest08Begin = $('#rest08Begin').val();
obj.rest08End = $('#rest08End').val();
obj.rest09Begin = $('#rest09Begin').val();
obj.rest09End = $('#rest09End').val();
return obj;
}
/**
* 执行添加
*/
function executeAdd() {
if(!$("#addForm").form("validate")) {
return;
}
var obj = getDialogData();
var result = timeJudgement();
if(result != "false") {
hyapp.showInfo("提示", result);
return;
}
if(obj.id != null) {
hyapp.ajaxPost(hyapp.getContextPath() + "/basic/restPeriod/addOrEditRest", obj, function(result) {
if(result.success) {
$("#addDialog").dialog("close");
doSearch();
hyapp.showInfo("提示", result.msgText);
}
}, function(result) {
hyapp.showInfo("异常", result.msgText);
});
}
}
/**
* 时间段是否合适判断
* @returns {String}
*/
function timeJudgement() {
var time = [];
time[0] = $('#rest01Begin').val();
time[1] = $('#rest01End').val();
time[2] = $('#rest02Begin').val();
time[3] = $('#rest02End').val();
time[4] = $('#rest03Begin').val();
time[5] = $('#rest03End').val();
time[6] = $('#rest04Begin').val();
time[7] = $('#rest04End').val();
time[8] = $('#rest05Begin').val();
time[9] = $('#rest05End').val();
time[10] = $('#rest06Begin').val();
time[11] = $('#rest06End').val();
time[12] = $('#rest07Begin').val();
time[13] = $('#rest07End').val();
time[14] = $('#rest08Begin').val();
time[15] = $('#rest08End').val();
time[16] = $('#rest09Begin').val();
time[17] = $('#rest09End').val();
for(var i = 0; i < time.length; i = i + 2) {
if((time[i] == "" && time[i + 1] == "")) {
continue;
}
if((time[i] != "" && time[i + 1] == "") ||
(time[i] == "") && (time[i + 1] != "")) {
return "请把时间段填写完整!";
}
if(time[i] == time[i + 1]) {
return "开始和结束时间不能相同!";
}
}
for(var i = 0; i < time.length; i = i + 2) {
if(time[i] == "" || time[i + 1] == "") {
continue;
}
for(var j = i + 2; j < time.length; j = j + 2) {
if(time[j] == "" || time[j + 1] == "") {
continue;
}
var flag = checkTime(time[i], time[i + 1], time[j], time[j + 1]);
if(flag) {
return "时间段冲突!";
}
}
}
return "false";
}
/**
* 删除
*/
function doRemove() {
var selectRows = $("#dataGrid").datagrid("getSelections");
if(selectRows.length <= 0) {
hyapp.showInfo("提示", "请选择要操作的数据!");
return;
}
var idList = [];
for(var i = 0; i < selectRows.length; i++) {
idList.push(selectRows[i].id);
}
hyapp.showConfirm('请确认', '您确定要删除当前选中数据吗?', function() {
hyapp.ajaxPost(hyapp.getContextPath() + "/basic/restPeriod/removeRest", idList,
function(result) {
doSearch();
hyapp.showInfo("提示", result.msgText);
},
function(xhr, status) {
hyapp.showError("错误", result.msgText)
});
});
}
/**
* 编辑
*/
function doEdit() {
var selRows = $('#dataGrid').datagrid('getSelections');
if(selRows.length == 1) {
openEditDialog(selRows[0]);
} else {
if(selRows.length == 0) {
hyapp.showInfo("提示", "请选择要操作的数据!");
} else {
hyapp.showInfo("提示", "请选择一条数据!");
}
}
}
/**
* 清空编辑框
*/
function clearDialog() {
$('#addForm').form('clear');
}
/**
* 打开编辑对话框
*/
function openEditDialog(row) {
$('#addForm').form('clear');
if(row) {
$('#id').val(row.id);
$("#restName").textbox("setText", row.restName);
$('#rest01Begin').val(row.rest01Begin);
$('#rest01End').val(row.rest01End);
$('#rest02Begin').val(row.rest02Begin);
$('#rest02End').val(row.rest02End);
$('#rest03Begin').val(row.rest03Begin);
$('#rest03End').val(row.rest03End);
$('#rest04Begin').val(row.rest04Begin);
$('#rest04End').val(row.rest04End);
$('#rest05Begin').val(row.rest05Begin);
$('#rest05End').val(row.rest05End);
$('#rest06Begin').val(row.rest06Begin);
$('#rest06End').val(row.rest06End);
$('#rest07Begin').val(row.rest07Begin);
$('#rest07End').val(row.rest07End);
$('#rest08Begin').val(row.rest08Begin);
$('#rest08End').val(row.rest08End);
$('#rest09Begin').val(row.rest09Begin);
$('#rest09End').val(row.rest09End);
}
$('#addForm').form('validate');
$('#addDialog').dialog('open');
}
/**
* 加载完成后
*/
function handleLoadSuccess(data) {
$('#dataGrid').datagrid('clearSelections');
}
/**
* 双击
*/
function handleDblClick(index, row) {
$('#dataGrid').datagrid("unselectAll");
$('#dataGrid').datagrid("selectRow", index);
// console.log(index);
openEditDialog(row);
}
/**
* 没有跨天时,验证是否冲突。
* @param a
* @param b
* @param x
* @param y
* @returns {Boolean}
*/
function check(a, b, x, y) {
if(y < a || b < x) {
return false;
} else {
return true;
}
}
/**
*
* @param a
* @param b
* @param x
* @param y
* @returns {Boolean}
*/
function checkTime(a, b, x, y) {
var times1 = [],
times2 = [];
if(a < b) {
//未跨天
times1.push([a, b]);
} else {
//跨天
times1.push([a, "24:00"], ["00:00", b]);
}
if(x < y) {
times2.push([x, y]);
} else {
times2.push([x, "24:00"], ["00:00", y]);
}
//循环比较时间段是否冲突
for(var i = 0; i < times1.length; i++) {
for(var j = 0; j < times2.length; j++) {
if(check(times1[i][0], times1[i][1], times2[j][0], times2[j][1])) {
return true;
}
}
}
return false;
}
这里最重要的就是check方法和checkTime方法了,check方法是仅用来比较2个时间段是否有交集,而且这两个时间段都没有进行跨天的(也就是结束时间>起始时间)。
那么跨天的时间段怎么验证是否有交集呢?我们可以把跨天的时间段分为两部分,一部分是起始时间——24:00,另一部分是00:00——结束时间,所以我们只需要验证一个时间段例如2:00——6:00和这两个时间段没有交接即可(注意是3个时间段互相没有交集),这样就可以说明这个2:00——6:00的时间段和这个跨天的时间段没有交集了。
另外,需要注意的是,在进行校验的时候,验证时间段的起始和结束是否存在用的都是time[i]==" ",用的是空串的形式,这是因为通过 obj.rest01End = $('#rest01End').val();得到的数据是字符串的形式,如果在页面没有选择时间,那么得到的是一个空字符串“ ”。下面的数组就是我在前天debug获取的。
- 0: "18:30"
- 1: "19:00"
- 2: ""
- 3: ""
- 4: " "
- 5: " "
- 6: " "
- 7: " "
- 8: " "
- 9: " "
- 10: " "
- 11: " "
- 12: " "
- 13: " "
- 14: " "
- 15: " "
- 16: " "
- length: 17
- __proto__: Array(0)
那么这里又要有疑问了,既然是字符串那么是怎么比较大小的呢?
其实字符串的比较是按ASCII码的大小来比较的。从左到右逐位比较字符的ASCII码,只要分出大小,比较即结束。例如:
alert("2">"222"); 为:false
alert("3">"222"); 为:true
数字是这样,字符串也是如此,“ccc”肯定是要大于“aaa”的,既 “ ccc ” > " aaa "。
四.和博客不想关的东西
这里说一个和这篇博客没有关系的几个东西。
1.combobox下拉框,读取数据是从json数组中读取的。通过valueField属性来指定每一个下拉框的value值,通过textField来指定每个下拉框中的文本值。如果这个combobox下拉框在一个form表单中,当我们清空这个表单内的值时( $('#addForm').form('clear');),会清空这个combobox下拉框的值,而不是清空这个下拉框读取数据的json数组。所以在页面的体现就是当form表单被清空后,下拉框中的文本值会被清空,但是下拉框面板中的值依旧存在,当我们指定赋值value的时候,对应value的值会出现在下拉框的text中。
2. form表单的clear()方法,用于清空表单中所有输入项的value值。reset()方法,如果输入框有 默认值,则恢复到其默认的value值,否则清空value值。
3.动态删除集合中的数据是会导致出现问题的。
4.$.messager对象可以用来提示信息,通常可以在页面向用户显示提示框。