You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js倒计时器:按9小时工作日计算截止时间需求

Vue.js 工作日倒计时器(按每日9小时计算)

以下是修改后的完整代码,实现了按**每日9小时工作日(上午9点至下午6点)**计算截止时间的逻辑,满足18小时对应2个工作日、20小时对应2个工作日加2小时的需求:

修改后的JavaScript代码

var application = new Vue({
  data: {
    countdownData: {
      startDateTime: null,
      startHour: 9,
      endHour: 18,
      tenure: 1,
      time: {
        total: 0,
        days: 0,
        hours: 0,
        minutes: 0,
        seconds: 0,
      },
      deadline: null,
      paused: false,
      timeLeft: 0,
      timeInterval: null,
      countdownActive: false,
      offDays: 0,
    },
  },
  filters: {
    formatDate: function (value) {
      if (value) {
        const options = { year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' };
        return new Date(value).toLocaleDateString('zh-CN', options);
      }
      return '';
    },
  },
  methods: {
    timeRemaining(endtime) {
      const t = Date.parse(endtime) - Date.now();
      const seconds = Math.floor((t / 1000) % 60);
      const minutes = Math.floor((t / 1000 / 60) % 60);
      const hours = Math.floor((t / (1000 * 60 * 60)) % 24);
      const days = Math.floor(t / (1000 * 60 * 60 * 24));
      return { total: t, days, hours, minutes, seconds };
    },
    runClock() {
      this.updateClock();
      this.countdownData.timeInterval = setInterval(this.updateClock, 1000);
    },
    updateClock() {
      const currentTime = new Date();
      const isWithinWorkingHours =
        currentTime.getHours() >= this.countdownData.startHour &&
        currentTime.getHours() < this.countdownData.endHour;

      if (isWithinWorkingHours) {
        this.countdownData.countdownActive = true;
        this.countdownData.time = this.timeRemaining(
          this.countdownData.deadline
        );
        if (this.countdownData.time.total <= 0) {
          clearInterval(this.countdownData.timeInterval);
        }
      } else {
        this.stopClock();
        this.countdownData.countdownActive = false;
      }
    },
    pauseClock() {
      if (!this.countdownData.paused) {
        this.countdownData.paused = true;
        clearInterval(this.countdownData.timeInterval);
        this.countdownData.timeLeft = this.countdownData.time.total;
      }
    },
    resumeClock() {
      if (this.countdownData.paused) {
        this.countdownData.paused = false;
        this.countdownData.deadline = new Date(
          Date.now() + this.countdownData.timeLeft
        );
        this.runClock();
      }
    },
    handleInput() {
      this.stopClock();
      this.countdownData.deadline = this.calculateDeadline();
      this.runClock();
    },
    stopClock() {
      clearInterval(this.countdownData.timeInterval);
    },
    calculateDeadline() {
      if (!this.countdownData.startDateTime) return null;

      const start = new Date(this.countdownData.startDateTime);
      let remainingHours = this.countdownData.tenure;
      const workHoursPerDay = this.countdownData.endHour - this.countdownData.startHour;
      let currentDate = new Date(start);

      // 处理起始时间不在工作时段的情况
      const isStartInWorkHours = currentDate.getHours() >= this.countdownData.startHour && currentDate.getHours() < this.countdownData.endHour;
      if (!isStartInWorkHours) {
        if (currentDate.getHours() < this.countdownData.startHour) {
          // 早于上班时间,跳到当天上班点
          currentDate.setHours(this.countdownData.startHour, 0, 0, 0);
        } else {
          // 晚于下班时间,跳到下一个工作日(含休息日)的上班点
          currentDate.setDate(currentDate.getDate() + 1 + this.countdownData.offDays);
          currentDate.setHours(this.countdownData.startHour, 0, 0, 0);
        }
      }

      // 逐天消耗剩余时长
      while (remainingHours > 0) {
        const todayEnd = new Date(currentDate);
        todayEnd.setHours(this.countdownData.endHour, 0, 0, 0);
        const remainingTodayHours = (todayEnd - currentDate) / (1000 * 60 * 60);

        if (remainingHours <= remainingTodayHours) {
          // 剩余时长可在当天完成
          currentDate.setHours(currentDate.getHours() + remainingHours);
          remainingHours = 0;
        } else {
          // 消耗当日剩余时间,跳转到下一个工作日
          remainingHours -= remainingTodayHours;
          currentDate.setDate(currentDate.getDate() + 1 + this.countdownData.offDays);
          currentDate.setHours(this.countdownData.startHour, 0, 0, 0);
        }
      }

      return currentDate;
    },
  },
  beforeDestroy() {
    this.stopClock();
  },
  mounted() {
    this.handleInput();
  },
}).$mount('#app');

HTML代码(适配中文显示)

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <table class="table table-bordered">
    <tbody>
      <tr>
        <td>
          <label for="startDateTimeInput">输入开始日期时间:</label>
          <input
            type="datetime-local"
            id="startDateTimeInput"
            v-model="countdownData.startDateTime"
            @input="handleInput"
            class="form-control"
          />
        </td>
        <td>
          <label for="tenureInput">输入时长(小时):</label>
          <input
            type="number"
            id="tenureInput"
            v-model="countdownData.tenure"
            @input="handleInput"
            class="form-control"
            min="1"
          />
        </td>
        <td>
          <label for="offDaysInput">输入休息日天数:</label>
          <input
            type="number"
            id="offDaysInput"
            v-model="countdownData.offDays"
            @input="handleInput"
            class="form-control"
            min="0"
          />
        </td>
      </tr>
    </tbody>
  </table>
  <div v-if="countdownData.countdownActive">
    <div class="mx-auto" id="clockdiv">
      <h2 class="text-center text-danger">{{ countdownData.time.hours }}: {{ countdownData.time.minutes }} :{{ countdownData.time.seconds }}</h2>
    </div>
    <div class="text-center">
      <p>截止时间: {{ countdownData.deadline | formatDate }}</p>
    </div>
    <div class="d-flex justify-content-center">
      <button class="btn btn-primary mr-2" type="button" @click="pauseClock">暂停</button>
      <button class="btn btn-primary" type="button" @click="resumeClock">继续</button>
    </div>
  </div>
  <div v-else>
    <p>倒计时仅在工作时段内激活。</p>
  </div>
</div>

关键修改说明

  1. 核心逻辑重写:完全重构calculateDeadline方法,实现工作日时长计算规则,自动处理起始时间不在工作时段的情况,逐天消耗剩余时长并跳过休息日
  2. 本地化适配:将日期显示改为中文格式,更符合国内使用习惯
  3. 功能兼容:保留原有暂停/继续、实时倒计时更新等功能,仅修改截止时间计算逻辑

内容的提问来源于stack exchange,提问作者rahi bd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 20:42:03