|
@@ -0,0 +1,79 @@
|
|
|
+import dayjs from 'dayjs';
|
|
|
+import minMax from 'dayjs/plugin/minMax';
|
|
|
+dayjs.extend(minMax);
|
|
|
+/**
|
|
|
+ * 每莱得加班工时和正常工时计算
|
|
|
+ * @param {string} startDateTimeStr YYYY-MM-DD HH:mm:ss
|
|
|
+ * @param {string} endDateTimeStr YYYY-MM-DD HH:mm:ss
|
|
|
+ * @param {Array} restPeriods [{ start: HH:mm:ss, end: HH:mm:ss }]
|
|
|
+ * @returns
|
|
|
+ */
|
|
|
+export function calculateWorkHours(startDateTimeStr, endDateTimeStr, restPeriods = []) {
|
|
|
+ const start = dayjs(startDateTimeStr);
|
|
|
+ const end = dayjs(endDateTimeStr);
|
|
|
+
|
|
|
+ if (!start.isValid() || !end.isValid() || end.isBefore(start)) return { workHours: 0, overtimeHours: 0 };
|
|
|
+
|
|
|
+ // 全部工作时长(秒)
|
|
|
+ let totalSeconds = end.diff(start, 'second');
|
|
|
+
|
|
|
+ // 计算休息时间重叠(秒)
|
|
|
+ let restSeconds = 0;
|
|
|
+ restPeriods.forEach(period => {
|
|
|
+ const restStart = dayjs(`${start.format('YYYY-MM-DD')} ${period.start}`);
|
|
|
+ const restEnd = dayjs(`${start.format('YYYY-MM-DD')} ${period.end}`);
|
|
|
+ const overlapStart = dayjs.max(start, restStart);
|
|
|
+ const overlapEnd = dayjs.min(end, restEnd);
|
|
|
+ if (overlapEnd.isAfter(overlapStart)) {
|
|
|
+ restSeconds += overlapEnd.diff(overlapStart, 'second');
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const netSeconds = totalSeconds - restSeconds;
|
|
|
+ const workHours = +(netSeconds / 3600).toFixed(1);
|
|
|
+
|
|
|
+ // 计算正常工作时段重叠(扣除休息时间)
|
|
|
+ const normalStart = dayjs(`${start.format('YYYY-MM-DD')} 09:00:00`);
|
|
|
+ const normalEnd = dayjs(`${start.format('YYYY-MM-DD')} 17:30:00`);
|
|
|
+ let normalSeconds = 0;
|
|
|
+
|
|
|
+ const overlapStart = dayjs.max(start, normalStart);
|
|
|
+ const overlapEnd = dayjs.min(end, normalEnd);
|
|
|
+
|
|
|
+ if (overlapEnd.isAfter(overlapStart)) {
|
|
|
+ let normalRest = 0;
|
|
|
+ restPeriods.forEach(period => {
|
|
|
+ const restStart = dayjs(`${start.format('YYYY-MM-DD')} ${period.start}`);
|
|
|
+ const restEnd = dayjs(`${start.format('YYYY-MM-DD')} ${period.end}`);
|
|
|
+ const restOverlapStart = dayjs.max(overlapStart, restStart);
|
|
|
+ const restOverlapEnd = dayjs.min(overlapEnd, restEnd);
|
|
|
+ if (restOverlapEnd.isAfter(restOverlapStart)) {
|
|
|
+ normalRest += restOverlapEnd.diff(restOverlapStart, 'second');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ normalSeconds = overlapEnd.diff(overlapStart, 'second') - normalRest;
|
|
|
+ }
|
|
|
+
|
|
|
+ const normalHours = +(normalSeconds / 3600).toFixed(1);
|
|
|
+ const overtimeHours = +(workHours - normalHours).toFixed(1);
|
|
|
+
|
|
|
+ const workTimes = workHours - (overtimeHours > 0 ? overtimeHours : 0)
|
|
|
+
|
|
|
+ return {
|
|
|
+ totalHours: workHours,
|
|
|
+ workHours: workTimes,
|
|
|
+ overtimeHours: overtimeHours > 0 ? overtimeHours : 0
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 获取唯一标识
|
|
|
+ * @returns string
|
|
|
+ */
|
|
|
+export function generateUUID() {
|
|
|
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
|
+ var r = Math.random() * 16 | 0,
|
|
|
+ v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
|
+ return v.toString(16);
|
|
|
+ });
|
|
|
+}
|