const countConst = { "workHours": 7,//每天的工作时长 "noonStartBreakTime": 12,//午休开始时间 12:00 "noonEndBreakTime": 14,//午休结束时间 14:30 "workStartTime": 9,//上班时间 8:30 "workEndTime": 18,//下班时间 18:00 "morningHours": 3,//上午上班时长 "afternoonHours": 4,//下午上班时长 "noonHours": 2//午休总时长 }; /** * 计算请假时长 * @param {string} start 请假开始时间 格式 2023-01-01 08:00:00 * @param {string} end 请假结束时间 * @param {string} vacateType 请假类型 * @param {string} isMakeUpForWork 是否补班时段请假,true才能选择休息日请假 */ export default { getLeaveHours(start, end, vacateType, isMakeUpForWork) { console.log(start); console.log(end); //请假总时长 let totalDurationLeave = 0; //请假开始和结束时间必须在8:30-12:00或14:30-18:00里面 var startTime = new Date(start.replace(/-/g, '/')); var endTime = new Date(end.replace(/-/g, '/')); //验证请假时间是否符合 if (!this.verifyTime(startTime, vacateType, isMakeUpForWork) || !this.verifyTime(endTime, vacateType, isMakeUpForWork)) { // alert("请假时间必须在8:30-12:00或14:30-18:00"); return 0; } if (endTime.getTime() < startTime.getTime()) { alert("开始时间必须小于结束时间!"); return 0; } //两时间的毫秒差 let ms = Math.abs(endTime.getTime() - startTime.getTime()); // console.log("毫秒差="+ms); //相差时长 let subtractionHours = this.accDiv(ms, 1000 * 60 * 60); // console.log("时间差="+subtractionHours); if (subtractionHours < 2) { alert("请假时长至少两小时!"); return 0; } //需要减去的午休总时长 let subtractNoonHours = 0; //开始时间的几号 let startDay = startTime.getDate(); // console.log("startDay",startDay); //结束时间的几号 let endDay = endTime.getDate(); // console.log("endDay",endDay); //开始时间的小时 let startHours = startTime.getHours(); //结束时间的小时 let endHours = endTime.getHours(); //开始时间的分钟 let startMinutes = startTime.getMinutes(); //结束时间的分钟 let endMinutes = endTime.getMinutes(); //日期差 let subtractDay = endDay - startDay; //请1天及以内 if (subtractionHours < 24 && subtractDay == 0) { //这属于跨午休了 if (startHours <= 12 && endHours >= 14) { subtractNoonHours = countConst.noonHours; } totalDurationLeave = this.accSub(subtractionHours, subtractNoonHours); return totalDurationLeave; } else {//请1天以上 //请假天数=日期差+1; let day = this.accAdd(subtractDay, 1); // console.log("day==="); // console.log(day); /** * 计算第一天请假时长 */ //分钟转换成小时 var minutesToHours = this.accDiv(startMinutes, 60); // console.log("转换分钟:"+minutesToHours); //请假小时数 例如:8:30为8.5 let morningH = this.accAdd(startHours, minutesToHours); // console.log("请假小时:"+morningH); //第一天请假时长 let oneDayLeaveHours = this.getOneDayLeaveDuration(startHours, morningH); // console.log("第一天请假时长:"+oneDayLeaveHours); /** * 计算最后一天请假时长 */ //分钟转换成小时 var endMinutesToHours = this.accDiv(endMinutes, 60); // console.log("转换分钟:"+endMinutesToHours); //上午请假时长 let endMorningH = this.accAdd(endHours, endMinutesToHours); //请假小时数 例如:8:30为8.5 // console.log("请假小时:"+endMorningH); //最后一天请假时长 let endDayLeaveHours = this.getEndDayLeaveDuration(endHours, endMorningH); // console.log("最后一天请假时长:"+endDayLeaveHours); //中间跨的天数=(总跨天数-前后天数(2天))*每天工作时长 let daySpan = this.accSub(day, 2); daySpan = this.accMul(daySpan, countConst.workHours); //请假总时长=第一天请假时长+(总跨天数-2)*每天工作时长+最后一天请假时长 totalDurationLeave = this.accAdd(oneDayLeaveHours, endDayLeaveHours); totalDurationLeave = this.accAdd(totalDurationLeave, daySpan); /** * 只有产假会把星期天和星期六算进去 * 周末排除 * */ if (vacateType != '5' && isMakeUpForWork == "false") { let restDay = this.weekendBetween(start, end); // console.log("其中休息日的天数"); // console.log(restDay); //休息日大于0 不是产假 if (restDay > 0) { //实际请假总时长=请假总时长-(休息日*每天工作时长) let restDayTime = this.accMul(restDay, countConst.workHours); totalDurationLeave = this.accSub(totalDurationLeave, restDayTime); } } return totalDurationLeave; } }, /** * 判断请假时间里面有多少个周末 */ // console.log("09-04~10-20"); // console.log(weekendBetween("2023-09-01 08:30:00","2023-10-20 18:00:00")); weekendBetween(dtStart, dtEnd) { console.log(1111); //休息日 let tRestDay = 0; /** * 时间处理,把时分秒设为一致的,方便计算 */ var dataStartRest = dtStart.split(" "); var restStartDate = dataStartRest[0]; var dataEndRest = dtEnd.split(" "); var restEndDate = dataEndRest[0]; var restStartDateStr = restStartDate + " 08:00:00"; var restEndDateStr = restEndDate + " 08:00:00"; var startTime = new Date(restStartDateStr.replace(/-/g, '/')); var endTime = new Date(restEndDateStr.replace(/-/g, '/')); /** * 获取时间的各种值 */ //星期 let dayStart = startTime.getDay(); let dayEnd = endTime.getDay(); //日期 let dateStart = startTime.getDate(); let dateEnd = endTime.getDate(); //一个小时的毫秒数 let hoursMs = 1000 * 60 * 60; //一天的毫秒数 let dayMs = hoursMs * 24; //日期转为毫秒 let timeStart = startTime.getTime(); let timeEnd = endTime.getTime(); //两时间的毫秒差 let ms = Math.abs(endTime.getTime() - startTime.getTime()); //间隔小时 let intervalHours = this.accDiv(ms, hoursMs); //间隔天数 let intervalDay = this.accDiv(ms, dayMs); let dateTimeStr = endTime.getTime(); var dateTime = ""; //计算间隔中有多少休息日 for (var i = 0; i < intervalDay; i++) { //第一次以默认值计算 if (i != 0) { dateTimeStr = this.accSub(dateTimeStr, dayMs); } dateTime = this.getSpeTime(dateTimeStr); var dateNowTime = new Date(dateTime.replace(/-/g, '/')); if (dateNowTime.getDay() == 6 || dateNowTime.getDay() == 0) { // console.log(dateTime); tRestDay++; } } return tRestDay; }, getSpeTime(timeStr) { var dateSpe = new Date(parseInt(timeStr)); // console.log("dateSpe====") // console.log(dateSpe) // timeStr是毫秒值 // 获取年份 var year = dateSpe.getFullYear(); //获取月份,获取的月份比实际小1,所以需要+1 var month = dateSpe.getMonth() + 1; if (month < 10) { month = '0' + month } //获取日 var date = dateSpe.getDate(); if (date < 10) { date = '0' + date } //获取时 var hours = dateSpe.getHours(); if (hours < 10) { hours = '0' + hours } //获取分 var minutes = dateSpe.getMinutes(); if (minutes < 10) { minutes = '0' + minutes } //获取秒 var seconds = dateSpe.getSeconds(); if (seconds < 10) { seconds = '0' + seconds } //组合格式为年-月-日 时:分:秒(2022-6-6 12:12:12) return year + "-" + month + "-" + date + " " + hours + ":" + minutes + ":" + seconds; }, /** * 毫秒数转换成日期格式 */ convertMillisecondsToDate(milliseconds) { const date = new Date(milliseconds); const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); const hours = date.getHours(); const minutes = date.getMinutes(); const seconds = date.getSeconds(); let dateString = `${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day} ${hours < 10 ? '0' + hours : hours}:${minutes < 10 ? '0' + minutes : minutes}:${seconds < 10 ? '0' + seconds : seconds}`; return dateString; }, /** * 获取第一天请假时长 * @param {Object} hours 请假的小时 例如:8:30记作8 * @param {Object} realityLeaveHours 实际请假的小时 例如:8:30记作8.5 */ getOneDayLeaveDuration(hours, realityLeaveHours) { //上午或下午请假时长 let noeMorningHours = 0; //请假实际时长 let leaveHours = 0; //判断请假时间是上午还是下午 //请假时间<=上午下班时间 是上午请假 if (hours <= countConst.noonStartBreakTime) { //用上午下班时间-实际请假的小时=早上请假时长 noeMorningHours = this.accSub(countConst.noonStartBreakTime, realityLeaveHours); //第一天请假时长=下午工作时长+早上请假时长 leaveHours = this.accAdd(countConst.afternoonHours, noeMorningHours); } else {//下午请假 //下午请假时长=下午下班时间-实际请假的小时 noeMorningHours = this.accSub(countConst.workEndTime, realityLeaveHours); //第一天请假时长=下午请假时长 leaveHours = noeMorningHours; } return leaveHours; }, /** * 获取最后一天请假时长 * @param {Object} hours 请假的小时 例如:8:30记作8 * @param {Object} realityLeaveHours 实际请假的小时 例如:8:30记作8.5 */ getEndDayLeaveDuration(hours, realityLeaveHours) { //上午或下午请假时长 let noeMorningHours = 0; //请假实际时长 let leaveHours = 0; //判断请假时间是上午还是下午 //请假时间<=上午下班时间 是上午请假 if (hours <= countConst.noonStartBreakTime) { //早上请假时长=请假小时-早上上班时间 noeMorningHours = this.accSub(realityLeaveHours, countConst.workStartTime); //最后一天请假时长=早上请假时长 leaveHours = noeMorningHours; } else {//下午请假 //下午请假时长=实际请假的小时-下午上班时间 noeMorningHours = this.accSub(realityLeaveHours, countConst.noonEndBreakTime); //最后一天请假时长=下午请假时长+上午工作小时(3.5小时) leaveHours = this.accAdd(noeMorningHours, countConst.morningHours); } return leaveHours; }, /** * 验证请假时间是否在工作时间段 * @param {Object} time 请假时间 */ verifyTime(time, vacateType, isMakeUpForWork) { //小时 let tHours = time.getHours(); //分钟 let tMinutes = time.getMinutes(); //分钟转换成小时 let minutesToHours = this.accDiv(tMinutes, 60); //请假小时数 例如:8:30为8.5 let leaveH = this.accAdd(tHours, minutesToHours); //请假时间是否在工作时间 var isWorkTime = true; //不在工作时间 if (leaveH < countConst.workStartTime || leaveH > countConst.workEndTime) { alert("请假时间必须在8:30-12:00或14:30-18:00!") isWorkTime = false; } if (time.getSeconds() != 0) { alert("为了更准确的计算请假时长,请假时间的秒数请设置为00!") isWorkTime = false; } //不是产假的要判断请假时间不能选择星期六、星期天 // console.log("vacateType====") // console.log(vacateType) // console.log(isMakeUpForWork) if (vacateType != '5' && isMakeUpForWork == "false") { if (time.getDay() == 6 || time.getDay() == 0) { alert("请假时间不能选休息日(产假或勾选休息日请假除外)!") isWorkTime = false; } } //处于午休时间段 if (leaveH > countConst.noonStartBreakTime && leaveH < countConst.noonEndBreakTime) { // console.log("处于午休时间段"); isWorkTime = false; } // console.log("请假时间是否符合:"+isWorkTime); return isWorkTime; }, /** ** 加法函数,用来得到精确的加法结果 ** 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。 ** 调用:accAdd(arg1,arg2) ** 返回值:arg1加上arg2的精确结果 **/ accAdd(arg1, arg2) { var r1, r2, m, c; try { r1 = arg1.toString().split(".")[1].length; } catch (e) { r1 = 0; } try { r2 = arg2.toString().split(".")[1].length; } catch (e) { r2 = 0; } c = Math.abs(r1 - r2); // m = Math.pow(10, Math.max(r1, r2)); m = 10 ** Math.max(r1, r2); if (c > 0) { var cm = Math.pow(10, c); if (r1 > r2) { arg1 = Number(arg1.toString().replace(".", "")); arg2 = Number(arg2.toString().replace(".", "")) * cm; } else { arg1 = Number(arg1.toString().replace(".", "")) * cm; arg2 = Number(arg2.toString().replace(".", "")); } } else { arg1 = Number(arg1.toString().replace(".", "")); arg2 = Number(arg2.toString().replace(".", "")); } return (arg1 + arg2) / m; }, /** ** 减法函数,用来得到精确的减法结果 ** 说明:javascript的减法结果会有误差,在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。 ** 调用:accSub(arg1,arg2) ** 返回值:arg1减去arg2的精确结果 **/ accSub(arg1, arg2) { var r1, r2, m, n; try { r1 = arg1.toString().split(".")[1].length; } catch (e) { r1 = 0; } try { r2 = arg2.toString().split(".")[1].length; } catch (e) { r2 = 0; } m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度 n = (r1 >= r2) ? r1 : r2; return ((arg1 * m - arg2 * m) / m).toFixed(n); }, /** ** 乘法函数,用来得到精确的乘法结果 ** 说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。 ** 调用:accMul(arg1,arg2) ** 返回值:arg1乘以 arg2的精确结果 **/ accMul(arg1, arg2) { var m = 0, s1 = arg1.toString(), s2 = arg2.toString(); try { m += s1.split(".")[1].length; } catch (e) { } try { m += s2.split(".")[1].length; } catch (e) { } return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / (10 ** m) }, /** ** 除法函数,用来得到精确的除法结果 ** 说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。 ** 调用:accDiv(arg1,arg2) ** 返回值:arg1除以arg2的精确结果 **/ accDiv(arg1, arg2) { var t1 = 0, t2 = 0, r1, r2; try { t1 = arg1.toString().split(".")[1].length; } catch (e) { } try { t2 = arg2.toString().split(".")[1].length; } catch (e) { } r1 = Number(arg1.toString().replace(".", "")); r2 = Number(arg2.toString().replace(".", "")); return (r1 / r2) * (10 ** (t2 - t1)); } }