Vue前端对请假模块——请假开始时间和请假结束时间的校验处理

开发背景:Vue+element组件开发

业务需求:用户提交请假申请单,请假申请的业务逻辑处理

实现:用户选择开始时间需要大于本地时间,不得大于请假结束时间,请假时长根据每日工作时间实现累加计算

页面布局

在前端页面选择的是el-date-picker组件

 <!-- 请假开始时间表单项 -->
<el-form-item
  prop="start_time" <!-- 绑定表单验证规则的属性名 -->
  label="请假开始时间" <!-- 表单项标签文本 -->
  style="height: 55px" <!-- 设置表单项高度 -->
  label-width="120px" <!-- 设置标签宽度 -->
  :required="true" <!-- 标记为必填项 -->
>
  <el-col :span="11"> <!-- 使用 Element UI 的 Col 布局,设置列宽 -->
    <el-date-picker <!-- 日期时间选择器组件 -->
      type="datetime" <!-- 设置类型为日期和时间选择 -->
      placeholder="选择日期" <!-- 提示信息 -->
      v-model="form.start_time" <!-- 绑定到表单对象的 start_time 属性 -->
      style="width: 100%" <!-- 设置组件宽度为100% -->
      value-format="yyyy-MM-dd HH:mm:ss" <!-- 设置选中值的时间格式 -->
      :picker-options="pickerOptionsStart" <!-- 传入开始时间的选择器选项 -->
      @change="calculateLeaveHours" <!-- 当选择日期发生改变时触发的方法 -->
    ></el-date-picker>
  </el-col>
</el-form-item>

<!-- 请假结束时间表单项 -->
<el-form-item
  label="请假结束时间"
  style="height: 55px"
  prop="end_time"
  label-width="120px"
  :required="true"
>
  <el-col :span="11">
    <el-date-picker
      type="datetime"
      placeholder="选择日期"
      v-model="form.end_time" <!-- 绑定到表单对象的 end_time 属性 -->
      style="width: 100%"
      value-format="yyyy-MM-dd HH:mm:ss"
      :picker-options="pickerOptionsEnd" <!-- 传入结束时间的选择器选项 -->
      @change="calculateLeaveHours" <!-- 同样在结束时间改变时触发计算方法 -->
    ></el-date-picker>
  </el-col>
</el-form-item>

<!-- 请假时长(小时)展示表单项 -->
<el-form-item label="请假时长(小时)" prop="hours" label-width="120px">
  <el-input <!-- 输入框组件 -->
    v-model="form.hours" <!-- 绑定到表单对象的 hours 属性 -->
    disabled <!-- 设置输入框为禁用状态,仅用于显示计算出的请假时长 -->
  ></el-input>
</el-form-item>

用户选择开始时间的范围校验

 :picker-options="pickerOptionsStart"
          @change="calculateLeaveHours"

通过picker-options  vue动态绑定属性设定了选择器的自定义配置,例如开始时间需大于本地时间且需要小于结束时间

开始时间选择代码如下:

// pickerOptionsStart 定义开始时间选择器的自定义选项
pickerOptionsStart: {
  // disabledDate 是一个函数,用于决定日期选择器中哪些日期应被禁用(即不可选)
  disabledDate: (time) => {
    // 获取表单中结束时间的值
    let endDateVal = this.form.end_time;
    
    // 创建一个新的 Date 对象表示当前本地时间,并将其时间部分设置为0,确保包含今天整天的时间范围
    let now = new Date();
    now.setHours(0, 0, 0, 0);

    // 如果结束时间未设置,则只允许用户选择从当前时间(包含今天)到未来的所有时间
    if (!endDateVal) {
      return time.getTime() < now.getTime(); 
    }

    // 同时满足以下条件时,该日期将被禁用:
    // 1. 开始时间需大于等于当前本地时间
    // 2. 开始时间需小于结束时间
    return (
      // 时间戳比较:如果开始时间早于当前时间 或者 开始时间晚于已设置的结束时间,则禁用该日期
      time.getTime() < now.getTime() ||
      time.getTime() > new Date(endDateVal).getTime()
    );
  },
},

获取结束时间的值,如果有则从本地时间到结束时间,如果没有就从本地时间到未来的时间,创建Date对象来获取当前本地的时间,至于为什么需要包含今天整体的时间是因为如果只判断开始时间大于本地时间的话,在时间选择器里今天的日期也是被禁止掉了的,这对于用户的体验是不好的,同理,结束时间与开始时间类似,但是这个方法的缺陷便是用户可以在下午选择今天早上的时间,这对于业务是不满足的,后面会有解决方案

结束时间范围选择

如果用户先选择结束时间时,如:2-29,开始时间就只能从26-29进行选择

代码如下:

// pickerOptionsEnd 定义结束时间选择器的自定义选项
      pickerOptionsEnd: {
        // disabledDate 是一个函数,用于决定日期选择器中哪些日期应被禁用(即不可选)
        disabledDate: (time) => {
          // 获取表单中开始时间的值
          let beginDateVal = this.form.start_time;

          // 创建一个新的 Date 对象表示当前本地时间
          const currentDate = new Date();

          // 确保结束时间大于开始时间(如果开始时间已设置)
          if (beginDateVal) {
            return time.getTime() <= new Date(beginDateVal).getTime();
          }

          // 同时允许用户选择今天的日期作为结束时间,因此仅当结束时间早于当前时间才禁用
          return time.getTime() < currentDate.setHours(0, 0, 0, 0);
        },
      },

对于开始时间的校验

为了解决用户在当天可以选择任意的时间段以及计算请假时长,在开始时间和结束时间发生变化时便执行方法

methods: {
    //计算请假时长
    calculateLeaveHours() {}
    
}

当用户选择的开始时间小于本地时间的5分钟之前时(因为涉及到秒数,选择的开始时间会一直小于本地时间,为用户操作保留缓冲区间),提示用户并重置开始时间为本地时间,当结束时间小于本地时间时,则重置结束时间为选择的开始时间后一个小时

 const startTime = new Date(this.form.start_time);
      const endTime = new Date(this.form.end_time);

      let now = new Date();

      const fiveMinutesAgo = new Date();
      fiveMinutesAgo.setMinutes(now.getMinutes() - 5);
      fiveMinutesAgo.setSeconds(0);
      fiveMinutesAgo.setMilliseconds(0);

      if (startTime < fiveMinutesAgo) {
        this.$message({
          message: "开始时间需在当前时间附近,已为您选择当前时间!",
          type: "warning",
        });
        this.form.start_time = new Date();
      }

      if (endTime < startTime) {
        this.$message({
          message:
            "结束时间小于开始时间,已为您选择结束时间为开始时间后一个小时!",
          type: "warning",
        });
        this.form.end_time = new Date(startTime.getTime() + 60 * 60 * 1000);
      }

请假时长的计算

// 初始化请假时长
      let leaveHours = 0;

      // 计算每天的工作时间
      let currentDate = new Date(startTime);
      while (currentDate < endTime) {
        const currentHour = currentDate.getHours(); // 获取当前小时数
        const currentMinute = currentDate.getMinutes(); // 获取当前分钟数

        // 判断当前时间是否在工作时间段内,若在则加入工作时间
        if (
          // 上午工作时间段:8:30 - 11:20
          (((currentHour === 8 && currentMinute >= 30) || currentHour > 8) &&
            ((currentHour === 11 && currentMinute < 20) || currentHour < 11)) ||
          // 下午工作时间段:14:00 - 18:00
          ((currentHour === 14 || currentHour === 18) && currentMinute >= 0) ||
          (currentHour > 14 && currentHour < 18) ||
          // 晚上工作时间段:19:00 - 20:30
          (((currentHour === 19 && currentMinute >= 0) || currentHour > 19) &&
            ((currentHour === 20 && currentMinute <= 30) || currentHour < 20))
        ) {
          // 在工作时间段内,加入工作时间
          leaveHours += 0.1;
        }

        // 将日期增加一小时
        currentDate.setMinutes(currentMinute + 6); // 以6分钟为间隔加入工作时间
      }

      // 更新请假时长
      this.form.hours = leaveHours.toFixed(1);

这样的基本模块便完善得七七八八了,但在其中依然还是有些小问题,例如如果用户先选择时间结束后,再重置便会导致请假时长会一直计算的问题

最初想的解决方案是如果开始时间为空的话,就重置时间跳出方法,

// 首先检查开始时间和结束时间是否为空,如果任一为空则跳出此方法
      if (!this.form.start_time || !this.form.end_time) {
        return this.form.hours=0;
      }

但是如果用户选择的开始时间小于本地时间的话就不能再进行判断了,所以进行了优化

if (this.form.hours !=0 &&(!this.form.start_time || !this.form.end_time)) {
        return this.form.hours=0;
      }

这样便都解决了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/412006.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Excel PDF 系列】EasyExcel + iText 库

你知道的越多&#xff0c;你不知道的越多 点赞再看&#xff0c;养成习惯 如果您有疑问或者见解&#xff0c;欢迎指教&#xff1a; 企鹅&#xff1a;869192208 文章目录 前言转换前后效果引入 pom 配置代码实现定义 ExcelDataVo 对象主方法EasyExcel 监听器 前言 最近遇到生成 …

SQL进阶(三):Join 小技巧:提升数据的处理速度

复杂数据结构处理&#xff1a;Join 小技巧&#xff1a;提升数据的处理速度 本文是在原本sql闯关的基础上总结得来&#xff0c;加入了自己的理解以及疑问解答&#xff08;by GPT4&#xff09; 原活动链接 用到的数据&#xff1a;链接 提取码&#xff1a;l03e 目录 1. 课前小问…

动态规划之第 N 个泰波那契数/三步问题【leetCode】【算法】

动态规划动态规划之第 N 个泰波那契数/三步问题 动态规划LeetCode题目第 N 个泰波那契数求解1求解2&#xff08;滚动数组&#xff09; 三步问题求解1求解2&#xff08;滚动数组&#xff09; 动态规划 如果问题是由重叠的子问题构成的&#xff0c;那就可以用动态规划&#xff08…

JSON简介以及如何在Python中使用JSON

什么是JSON&#xff1f; JSON是"JavaScript Object Notation"的简称&#xff0c;是一种数据交换格式 JSON格式 假设我们有一个对象&#xff0c;这个对象有两个属性&#xff1a;“name”跟“age”。 在JSON中是这样表达的&#xff1a; { "name":"男孩…

【 C++ 】闭散列哈希表的模拟实现

哈希节点状态 我们都很清楚数组里的每一个值无非三种状态&#xff1a; 如果某下标没有值&#xff0c;则代表空EMPTY。如果有值在代表存在EXIST。如果此位置的值被删掉了&#xff0c;则表示为DELETE。 而这三种状态我们可以借助enum枚举来帮助我们表示数组里每个位置的状态。…

RK3568平台开发系列讲解(基础篇)如何快速学习一套 Linux开发板源码

🚀返回专栏总目录 文章目录 一、基础代码二、驱动代码沉淀、分享、成长,让自己和他人都能有所收获!😄 拿到一份源码和一块评估板,如何快速找到与这块板相关的源码,是很多研发人员都曾遇到过的问题。如果对内核源码结构有大概了解,要完成这些事情也不难,通常可按照基础…

ASLR 和 PIE

前言 ASLR&#xff08;Address Space Layout Randomization&#xff0c;地址空间随机化&#xff09;是一种内存攻击缓解技术&#xff0c;是一种操作系统用来抵御缓冲区溢出攻击的内存保护机制。这种技术使得系统上运行的进程的内存地址无法被预测&#xff0c;使得与这些进程有…

高性能 Kafka 及常见面试题

Kafka 是一种分布式的&#xff0c;基于发布/订阅的消息系统&#xff0c;原本开发自 LinkedIn&#xff0c;用作 LinkedIn 的事件流&#xff08;Event Stream&#xff09;和运营数据处理管道&#xff08;Pipeline&#xff09;的基础。 基础原理详解可见 Kafka 基本架构及原理 基础…

事件循环解析

浏览器的进程模型 何为进程&#xff1f; 程序运行需要有它自己专属的内存空间&#xff0c;可以把这块内存空间简单的理解为进程 每个应用至少有一个进程&#xff0c;进程之间相互独立&#xff0c;即使要通信&#xff0c;也需要双方同意。 何为线程&#xff1f; 有了进程后&…

Java根据excel模版导出Excel(easyexcel、poi)——含项目测试例子拿来即用

Java根据excel模版导出Excel&#xff08;easyexcel、poi&#xff09;——含项目测试例子拿来即用 1. 前言1.1 关于Excel的一般导出2.2 关于easyexcel的根据模版导出 2. 先看效果2.1 模版2.2 效果 3. 代码实现&#xff08;核心代码&#xff09;3.1 项目代码结构3.2 静态填充例子…

全域增长方法论:帮助品牌实现科学经营,助力长效生意增长

前两年由于疫情反复、供给需求收缩等条件制约&#xff0c;品牌业务均受到不同程度的影响。以双十一和618电商大促为例&#xff0c;就相比往年颇显“惨淡”&#xff0c;大多品牌营销都无法达到理想预期。 随着市场环境不断开放&#xff0c;2023年营销行业开始从低迷期走上了高速…

RPA中国 x UiPath | 第六届RPA极客挑战赛,3月16日上海开赛!

随着人工智能技术的不断进步以及数字化转型的深入&#xff0c;企业对于高效、精准、自动化的业务流程需求日益迫切。RPA技术作为连接人类工作与机器操作的桥梁&#xff0c;正逐渐从规则驱动发展为智能决策的助手。 由RPA中国联合UiPath共同主办的【第六届RPA极客挑战赛】将于2…

高性能API云原生网关 APISIX安装与配置指南

Apache APISIX是Apache软件基金会下的顶级项目&#xff0c;由API7.ai开发并捐赠。它是一个高性能的云原生API网关&#xff0c;具有动态、实时等特点。 APISIX网关可作为所有业务的流量入口&#xff0c;为用户提供了丰富的功能&#xff0c;包括动态路由、动态上游、动态证书、A…

【LeetCode每日一题】938. 二叉搜索树的范围和

2024-2-26 文章目录 [938. 二叉搜索树的范围和](https://leetcode.cn/problems/range-sum-of-bst/)思路&#xff1a;写法一&#xff1a;在中间累加写法二&#xff1a;在最后累加 938. 二叉搜索树的范围和 思路&#xff1a; 1.在二叉搜索树中&#xff1a;左子树的结点都小于根节…

【Excel PDF 系列】POI + iText 库实现 Excel 转换 PDF

你知道的越多&#xff0c;你不知道的越多 点赞再看&#xff0c;养成习惯 如果您有疑问或者见解&#xff0c;欢迎指教&#xff1a; 企鹅&#xff1a;869192208 文章目录 前言转换前后效果引入 pom 配置代码实现 前言 最近遇到生成 Excel 并转 pdf 的需求&#xff0c;磕磕碰碰总…

UE5 C++ Widget练习 Button 和 ProgressBar创建血条

一. 1.C创建一个继承Widget类的子类&#xff0c; 命名为MyUserWidget 2.加上Button 和 UserWidget的头文件 #include "CoreMinimal.h" #include "Components/Button.h" #include "Blueprint/UserWidget.h" #include "MyUserWidget.genera…

2步破解官方sublime4

sublime简要破解流程 1.下载sublime官方最新版2. 破解流程 1.下载sublime官方最新版 打开 官方网站下载 portable version 版&#xff0c;省的安装。。解压到任意位置&#xff0c;备份 sublime_text.exe 文件 2. 破解流程 打开网址把文件 sublime_text.exe 拖入网页搜索替换…

飞书公式留存

飞书公式留存 if(and(month([完成日期])>7,month([完成日期])<9),"Q3季度"&#xff0c;if(and(month([完成日期])>10,month([完成日期])<12),"Q4季度"&#xff0c;""))

基于YOLOv5+PySide6的火灾火情火焰检测系统设计深度学习

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;225火灾 获取完整源码源文件已标注的数据集&#xff08;1553张&#xff09;配置跑起来说明 可有偿49yuan一对一远程操作&#xff0c;在你电脑跑起来 效果展示&#xff1a; ​数据集在下载的文件夹&#xff1a;yolov5-5.0\…

抽象的后端

Connection refused: no further information 出现这条代码的核心是你使用redis&#xff0c;但是本地没有开启redis服务 如何启动redis服务 第一步&#xff1a;确定你安装了对应的框架 以spring为例 <dependency><groupId>org.springframework.boot</group…