排期组件实现文档

1. 项目概述

这个 Vue.js 组件是一个排期组件,用于在表格中选择一周内的时间段。具体的功能包括:

  • 鼠标拖动选择时间段
  • 选中时间段时,表格背景色变化
  • 在下方显示已选择的时间段信息
  • 清空按钮,清空所有已选择的时间段
2. 主要文件
  • 排期组件文件: ScheduleTable.vue
3. 主要组件及其功能
ScheduleTable.vue
  • 数据:

    • dayList: 包含星期一到星期日的数组。
    • schedule: 二维数组,表示每天的每个时间段的选中状态('0' 或 '1')。
    • isMouseDown: 用于判断鼠标是否按下。
    • startSelectionendSelection: 记录鼠标按下和松开时的位置。
  • 生命周期钩子:

    • mounted: 组件挂载时初始化默认排期。
  • 方法:

    • setDefaultSchedule: 初始化 schedule 数组为全 0。
    • clearSchedule: 清空所有选择的时间段。
    • toggleStatus: 切换时间段的选中状态。
    • handleMouseDown: 鼠标按下事件处理函数。
    • handleMouseMove: 鼠标移动事件处理函数。
    • handleMouseUp: 鼠标松开事件处理函数。
    • isCellSelected: 判断单元格是否在选中区域内。
    • updateSelectedCells: 更新选中区域内的状态。
    • caculateSchedule: 计算并更新时间段信息。
    • convertStringToTimeRanges: 将字符串数组转化为详细的时间范围。
4. 详细代码
<template>
  <div>
    <div class="header-des">
      <div class="item">
        <span class="isSelected block"></span>
        <span class="text">已选</span>
      </div>
      <div class="item">
        <span class="noSelected block"></span>
        <span class="text">未选</span>
      </div>
    </div>
    <table
      ref="scheduleTable"
      @mousedown="handleMouseDown"
      @mousemove="handleMouseMove"
      @mouseup="handleMouseUp"
    >
      <tr>
        <td class="col-name header-number header" rowspan="2">星期/时间</td>
        <td colspan="24" class="header-number header">00:00-12:00</td>
        <td colspan="24" class="header-number header">12:00-24:00</td>
      </tr>
      <tr>
        <td v-for="(i,index) in 24" colspan="2" :key="i" class="header-number">{{ index }}</td>
      </tr>
      <tr
        v-for="(day, dayIndex) in schedule"
        :key="dayIndex">
        <td class="col-name">{{ dayList[dayIndex] }}</td>
        <td
          v-for="(status, timeIndex) in day"
          :key="timeIndex"
          :class="{ selected: isCellSelected(dayIndex, timeIndex) ,col:true,isActive:status==='1'}"
          :data-day="dayIndex"
          :data-time="timeIndex"
        >
        </td>
      </tr>
    </table>
    <div class="days-info-wrap">
      <div class="empty" v-if="dayInfo.length===0">可拖动鼠标选择时间段</div>
      <div class="days-info" v-else>
        <div class="action-wrap">
          <div>已选择时间段</div>
          <div class="action" @click="clearSchedule()">清空</div>
        </div>
        <div v-for="(text,index) in dayInfo" :key="index" >
          <span class="info day-name" v-if="text">{{ dayList[index] }}</span>
          <span class="info day-content" v-if="text">{{ text }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dayList: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
      schedule: [], // 初始化schedule数据
      isMouseDown: false,
      startSelection: { day: -1, time: -1 },
      endSelection: { day: -1, time: -1 },
      dayInfo: []
    }
  },
  mounted() {
    // 设置默认全时段投放
    this.setDefaultSchedule()
    document.addEventListener('mouseup', () => {
      if (this.isMouseDown) {
        this.updateSelectedCells()
      }
    })
  },
  methods: {
    setDefaultSchedule() {
      // 将schedule数组初始化为全0
      this.schedule = Array.from({ length: 7 }, () => Array(48).fill('0'))
    },
    clearSchedule() {
      this.setDefaultSchedule()
      this.caculateSchedule()
      this.dayInfo = []
    },
    toggleStatus(dayIndex, timeIndex) {
      if (this.isMouseDown) {
      // 切换投放状态
        this.$set(this.schedule[dayIndex], timeIndex, this.schedule[dayIndex][timeIndex] === '1' ? '0' : '1')
      }
    },
    handleMouseDown(e) {
      if (e.target.dataset.day && e.target.dataset.time) {
        this.isMouseDown = true
        this.startSelection.day = parseInt(e.target.dataset.day)
        this.startSelection.time = parseInt(e.target.dataset.time)
        this.endSelection.day = parseInt(e.target.dataset.day)
        this.endSelection.time = parseInt(e.target.dataset.time)
      }
    },
    handleMouseMove(e) {
      if (this.isMouseDown && e.target.dataset.day && e.target.dataset.time) {
        this.endSelection.day = parseInt(e.target.dataset.day)
        this.endSelection.time = parseInt(e.target.dataset.time)
      }
    },
    handleMouseUp(e) {
      if (this.isMouseDown && e.target.dataset.day && e.target.dataset.time) {
        this.endSelection.day = parseInt(e.target.dataset.day)
        this.endSelection.time = parseInt(e.target.dataset.time)
        this.updateSelectedCells()
      }
    },
    isCellSelected(dayIndex, timeIndex) { // 判断单元格是否在选中区域内
      const start = this.startSelection
      const end = this.endSelection
      const inRowSelection = [Math.min(start.day, end.day), Math.max(start.day, end.day)]
      const inColumnSelection = [Math.min(start.time, end.time), Math.max(start.time, end.time)]
      return dayIndex <= inRowSelection[1] && dayIndex >= inRowSelection[0] && timeIndex <= inColumnSelection[1] && timeIndex >= inColumnSelection[0]
    },
    updateSelectedCells() {
      // 更新选中区域内的状态
      const start = this.startSelection
      const end = this.endSelection
      var list = []
      for (let day = Math.min(start.day, end.day); day <= Math.max(start.day, end.day); day++) {
        for (let time = Math.min(start.time, end.time); time <= Math.max(start.time, end.time); time++) {
          list.push(this.schedule[day][time])
        }
      }
      const length = [...new Set(list)].length
      for (let day = Math.min(start.day, end.day); day <= Math.max(start.day, end.day); day++) {
        for (let time = Math.min(start.time, end.time); time <= Math.max(start.time, end.time); time++) {
          if (length === 2) {
            this.$set(this.schedule[day], time, '1')
          } else {
            this.toggleStatus(day, time)
          }
        }
      }
      this.caculateSchedule()
      this.isMouseDown = false
      this.startSelection = {
        day: -1,
        time: -1
      }
      this.endSelection = {
        day: -1,
        time: -1
      }
    },
    caculateSchedule() {
      this.dayInfo = this.schedule.map(e => {
        return this.convertStringToTimeRanges(e).join('、')
      })
      this.$emit('schedule', this.schedule)
    },
    // 将字符串数组转化为详细的时间范围
    convertStringToTimeRanges(inputString) {
      const timeRanges = []
      let startTime = null

      for (let i = 0; i < inputString.length; i++) {
        const status = inputString[i]

        if (status === '1' && startTime === null) {
          // 进入新的时间段
          startTime = i * 0.5 // 每个时间段代表半个小时,所以乘以0.5得到小时数
        } else if (status === '0' && startTime !== null) {
          // 结束当前时间段
          const endTime = i * 0.5
          timeRanges.push({ start: startTime, end: endTime })
          startTime = null
        }
      }

      // 如果最后一个时间段一直到结尾,需要单独处理
      if (startTime !== null) {
        const endTime = 24 // 如果字符串长度为48,则结束时间为24小时
        timeRanges.push({ start: startTime, end: endTime })
      }
      function getText(params) {
        var str = ''
        if (params % 1 === 0) {
          str = params < 10 ? '0' + params + ':00' : params + ':00'
        } else {
          if (params < 10) {
            str = params < 10 ? '0' + parseInt(params) + ':' + (params % 1) * 60 : parseInt(params) + ':' + (params % 1) * 60
          } else {
            str = parseInt(params) + ':' + (params % 1) * 60
          }
        }
        return str
      }
      var dayList = timeRanges.map(e => {
        var startStr = getText(e.start)
        var endStr = getText(e.end)
        return startStr + '-' + endStr
      })
      return dayList
    }
  }
}
</script>

<style lang="less" scoped>
.header-des{
  height:30px ;
  line-height: 30px;
  padding: 0 10px;
  border: 1px solid #eee;
  border-bottom: none;
  display: flex;
  .item{
    margin-left: 10px;
    .block{
      display: inline-block;
      width: 15px;
      height: 7px;
      border-radius: 7px;
    }
    .isSelected{
      border: 1px solid #338aff;
      background: #338aff;
    }
    .noSelected{
      background: #fff;
      border: 1px solid #eee;
    }
    .text{
      display: inline-block;
      margin-left: 5px;
    }
  }
}
.header.header-number{
  height: 36px;
}
.header-number{
  height:26px;
  color: #333;
  font-size: 14px;
  font-weight: 700;
  background: #fff;
  cursor:pointer;
  text-align: center;
  border:1px solid #eee ;
}
.col{
  height:26px;
  width: 20px;
  color: #333;
  background: #fff;
  border:1px solid #eee ;
}
.col.selected,.col.isActive.selected{
  background-color: #b3d4fc;
}
.col.isActive{
 background: #338aff;
}
.col-name{
  height:26px;
  width: 80px;
  background: #fff;
  cursor: pointer;
  text-align: center;
  border:1px solid #eee ;
}
table:hover {
  user-select: none;
}
.days-info-wrap{
  min-height: 80px;
  width: 100%;
  border: 1px solid #eee;
  border-top: none;
  .empty{
    line-height: 80px;
    text-align: center;
    cursor: pointer;
  }
  .days-info{
    padding: 0 15px 15px;
    .action-wrap{
      height: 40px;
      line-height: 40px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      .action{
        color: #338aff;
        cursor: pointer;
      }
    }
    .info{
      display: inline-block;
      height: 26px;
      line-height: 26px;
      font-size: 14px;
    }
    .day-name{
      color: #333;
    }
    .day-content{
      font-size: 15px;
      margin-left: 5px;
    }
  }
}
</style>
5. 如何使用

在你的 Vue 项目中,可以按照以下步骤使用排期组件:

<template>
  <div>
    <ScheduleTable @schedule="handleScheduleChange" />
  </div>
</template>

<script>
import ScheduleTable from '@/components/ScheduleTable.vue';

export default {
  components: {
    ScheduleTable,
  },
  methods: {
    handleScheduleChange(schedule) {
      // 处理排期变化事件,schedule 参数为更新后的排期数据
      console.log('Updated Schedule:', schedule);
    },
  },
};
</script>
5.效果图

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IT开发表格期模板是指一种用于管理IT开发项目时间安的模板。在IT开发过程中,合理而准确地安时间是确保项目能够按时交付的关键。表格期模板可帮助团队成员了解项目所需的工作量和时间,并提前识别潜在的风险和延迟。 一个典型的IT开发表格期模板包括以下几个重要部分: 1. 项目概况:包括项目名称、项目经理、起止日期等基本信息。 2. 里程碑:列出项目的关键里程碑,这些里程碑是项目成功的关键节点。每个里程碑应包括开始日期、完成日期以及与之相关的任务和工作内容。 3. 任务列表:将项目分解为具体的任务,并为每个任务指定负责人和预计完成日期。这有助于明确每个人的责任,并确保项目按计划进行。 4. 依赖关系:展示项目中各个任务之间的依赖关系。这能够帮助团队成员了解哪些任务必须在其他任务完成后开始,避免出现不必要的延迟。 5. 资源分配:记录项目中可用资源的分配情况,包括人力资源、设备和资金。这有助于确保项目资源的合理利用和调配。 6. 风险评估和管理:对可能导致项目延迟的风险进行评估,并制定相应的风险应对策略。这有助于项目团队及时应对潜在问题,降低项目风险。 通过IT开发表格期模板,团队成员可以清晰地看到项目的时间安,知道自己的工作内容和截止日期。同时,项目经理也可以通过模板来跟踪项目进度,及时调整资源分配和解决潜在问题。 总之,IT开发表格期模板是IT项目管理中非常重要的工具,它能够帮助团队成员明确目标、合理分配资源、减少延迟风险,确保项目按计划顺利进行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值