会议室预约功能

index.js 

注:第一行引入jquery代码

import './jquery/jquery-3.4.1.min.js'
import setting from './setting.js';
function mergeOverlappingTimeRanges(timeRanges) {
  if (!timeRanges.length) return [];
  // 按照StartTime升序排序  
  timeRanges.sort((a, b) => new Date(a.StartTime) - new Date(b.StartTime));
  let merged = [timeRanges[0]]; // 初始化合并后的数组  
  for (let i = 1; i < timeRanges.length; i++) {
    let currentRange = timeRanges[i];
    let lastMergedRange = merged[merged.length - 1];

    // 如果当前时间段的开始时间在最后一个合并时间段的结束时间之前或相同  
    if (new Date(currentRange.StartTime) <= new Date(lastMergedRange.EndTime)) {
      // 更新最后一个合并时间段的EndTime为两个时间段中较晚的EndTime  
      lastMergedRange.EndTime = (new Date(currentRange.EndTime) > new Date(lastMergedRange.EndTime)) ? currentRange.EndTime : lastMergedRange.EndTime;
    } else {
      // 如果不重叠,则直接添加到merged数组  
      merged.push(currentRange);
    }
  }
  return merged;
}
function formatCurrentDate(now) {
  // 提取年份、月份、日期  
  const year = now.getFullYear(); // 获取完整的年份(4位,1970-????)  
  const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份是从0开始的,所以要加1  
  const day = String(now.getDate()).padStart(2, '0'); // 获取日(1-31)  

  // 拼接成YYYY-MM-DD格式  
  return `${year}-${month}-${day}`;
}
// 获取一周的日期数组
function getWeekDays(weekString) {
  const [year, weekNum] = weekString.split('-W').map(Number);
  let date = new Date(Date.UTC(year, 0, 4));
  date.setUTCDate(date.getUTCDate() - (date.getUTCDay() || 7) + 1);

  date.setUTCDate(date.getUTCDate() + (weekNum - 1) * 7);

  const weekDays = [];
  for (let i = 0; i < 7; i++) {
    const day = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
    weekDays.push(formatCurrentDate(day));
    date.setUTCDate(date.getUTCDate() + 1);
  }

  return weekDays;
}
// 通过日期获取当前的周数  格式为 YYYY-Www
function getISOWeekNumber(d) {
  d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
  // 星期四的日期(ISO 8601标准将周四视为一周的中间)  
  d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
  // 今年的第一天  
  var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
  // 计算今年的第一天是星期几(0=周日, 1=周一, ..., 6=周六)  
  var weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
  const year = d.getFullYear();
  return `${year}-W${weekNo}`;
}
class RoomClass {
  constructor(info) {
    // 设置初始化
    this.dataType = 'Day';
    // 展示的会议室
    this.list = [];
    // 元素
    this.ele = '';
    // 不可以选择的数据
    this.notInfo = {
      not: {},
      notMyself: {},
    }
    // 最大期次
    this.maxPeriod = 100;
    // 天时 默认值
    this.currentTime = formatCurrentDate(new Date());
    // 周时 默认值
    this.currentWeek = getISOWeekNumber(new Date());
    // 回调函数
    this.callback = function () { };
    // 当点击区域的事件
    this.callbackChangeArea = function () { };
    // 选择区域时产生变化的值
    this.selectBox = {
      active: null,
      StartTime: null,
      Day: {},
      Week: {},
    };
    // 设置绑定值
    if (info.ele) {
      this.ele = info.ele;
    }
    if (info.notInfo && info.notInfo.not) {
      this.notInfo.not = info.notInfo.not;
    }
    if (info.notInfo && info.notInfo.notMyself) {
      this.notInfo.notMyself = info.notInfo.notMyself;
    }
    if (info.list) {
      this.list = info.list;
    }
    if (info.changeArea) {
      this.callbackChangeArea = info.changeArea;
    }
    if (info.maxPeriod) {
      this.maxPeriod = info.maxPeriod;
    }
    // 回调事件
    if (info.change) {
      this.callback = info.change;
    }
  }
  // 初始化 引入css文件
  init() {
    const self = this; // 保存this的引用
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel = "stylesheet";
    link.href = '/room/index.css';
    document.head.appendChild(link);
    // 渲染基本元素
    this.renderBase();
    // 将元素增加到页面中
    if (this.list.length > 0) {
      this.resetTypeChangeData(this);
    }
    $(`${self.ele} .date-input`).on('change', function (e) {
      self.dataSelectChange(e.currentTarget, self);
    })
    // 绑定事件
    // 类型切换
    $(`${this.ele} .item-radio`).on('click', function (e) {
      self.typeChange(e.currentTarget, self);
    });

  }
  // 时间类型切换事件
  typeChange(ele, self) {
    $(ele).addClass('active-radio').siblings().removeClass('active-radio');
    self.dataType = $(ele).attr('key');
    self.resetTypeChangeData(self);
  }
  // 选择区域事件
  selectAreaData(ele, self) {
    const parent = $(ele).parent().parent();
    const currentEle = ele.getBoundingClientRect()
    // 当第一次点击时设置key值并新建元素
    if (!self.selectBox.active) {
      self.selectBox.StartTime = $(ele).attr('startTime');
      const left = currentEle.left - ele.offsetWidth / 2;
      self.selectBox.active = parent.attr('key');
      if (self.dataType === 'Day') {
        parent.find('.room-select-area-box').append(`<td class="room-item-select-box" style="left:${left + 4}px;"></td>`);
      } else {
        parent.find('.room-select-area-box').append(`<td class="room-item-select-box" style="left:${left + 10}px;"></td>`);
      }

      parent.on('mousemove', function (e) {
        self.mousemoveAreas(e, self, parent[0])
      })
    } else if (self.selectBox.active === parent.attr('key')) {
      // 当第二次点击时,是同一个元素时
      const oldEle = parent[0].getElementsByClassName('room-item-select-box')[0]
      const left = currentEle.left + ele.offsetWidth;
      // 当结束位置小于开始位置时,则清除选择
      if (left - oldEle.getBoundingClientRect().left < 0) {
        self.resetSelectLine(self);
        return;
      }
      // 将值保存
      const endTime = $(ele).attr('endTime');
      var data = {
        StartTime: self.currentTime + ' ' + self.selectBox.StartTime,
        EndTime: self.currentTime + ' ' + endTime,
      }
      if (self.dataType === 'Week') {
        data = {
          StartTime: self.selectBox.StartTime,
          EndTime: endTime,
        }
      }
      // 判断期间是否包含其他人的会议
      if (self.isIncludeMeeting(self, data)) {
        self.resetSelectLine(self);
        alert('其中包含其他会议,请重新选择')
        return;
      }
      // 进行弹窗 当成功之后,进行保存数据
      self.popupConfirm(self, data, () => {
        // 数据重置
        self.selectBox.active = null;
        parent.off('mousemove');
        oldEle.style.width = left - oldEle.getBoundingClientRect().left + 'px';
        parent.find('.room-item-select-box').attr('starttime', data.StartTime).attr('endtime', data.EndTime)
        parent.find('.room-item-select-box').removeClass('room-item-select-box').addClass('room-item-current-area')
        parent.find('.room-item-current-area').off('click');
        parent.find('.room-item-current-area').on('click', function (e) {
          self.changeArea(e.currentTarget, self);
        })
      })
    } else {
      // 当点击不同元素时
      self.resetSelectLine(self);
      self.selectAreaData(ele, self);
    }
  }
  // 判断当中是否包含其他人的会议
  isIncludeMeeting(self, data) {
    const key = self.selectBox.active;
    const myselfList = self.notInfo.notMyself[key];
    const notList = self.notInfo.not[key];
    const myselfIdx = myselfList.find(i => new Date(data.StartTime).getTime() <= new Date(i.StartTime).getTime() && new Date(data.EndTime).getTime() >= new Date(i.EndTime).getTime())
    const notIdx = notList.find(i => new Date(data.StartTime).getTime() <= new Date(i.StartTime).getTime() && new Date(data.EndTime).getTime() >= new Date(i.EndTime).getTime())
    if (notIdx || myselfIdx) {
      return true;
    }
    return false;
  }
  // 弹窗出现,进行选择确认
  popupConfirm(self, data, confirm) {
    // 获取最大人数
    const maxPeople = self.list.find(i => i.id === self.selectBox.active).maxPeople;
    // 设置弹窗信息
    $(`${self.ele} .room-select-box`).append(setting.confirmHtml(data.StartTime + '-' + data.EndTime, maxPeople, self.maxPeriod));
    // 关于输入框的处理
    $(`${self.ele} .popup-box .popup-content .form-value`).on('change', function (e) {
      const max = parseInt($(this).attr('max'));
      const min = parseInt($(this).attr('min'));
      const value = parseFloat($(this).val());
      if (value >= max) {
        $(this).val(max);
      }
      if (Number.isFinite(value) && value % 1 !== 0) {
        $(this).val(parseInt(value));
      }
      if (value < min) {
        $(this).val(min);
      }
    })
    // 当点击其他区域时,关闭弹窗
    $(`${self.ele} .popup-box`).on('click', () => {
      $(`${self.ele} .popup-box`).remove()
      self.resetSelectLine(self);
    })
    $(`${self.ele} .popup-box .popup-content`).on('click', function (event) { event.stopPropagation(); })
    // 当点击取消时
    $(`${self.ele} .btn-cancel`).on('click', () => {
      $(`${self.ele} .popup-box`).remove()
      self.resetSelectLine(self);
    })
    // 当点击确定时
    $(`${self.ele} .btn-confirm`).on('click', () => {
      const period = $(`${self.ele} .popup-box`).find('.value-period').val();
      const people = $(`${self.ele} .popup-box`).find('.value-people').val();
      self.saveLineData(self, self.selectBox.active, {
        ...data,
        period,
        people,
      })
      $(`${self.ele} .popup-box`).remove()
      confirm();
    })
  }
  // 当鼠标移动时的事件,时刻修改当前状态key的值
  mousemoveAreas(e, self, parent) {
    const currentEle = parent.getElementsByClassName('room-item-select-box')[0]
    if (currentEle) {
      currentEle.style.width = e.pageX - currentEle.getBoundingClientRect().left - 10 + 'px';
    }
  }
  // 渲染基本元素
  renderBase() {
    $(`${this.ele}`).html(setting.baseHtml(this.currentTime, this.currentWeek));
  }
  // 保存选择的区域数据
  saveLineData(self, key, value) {
    // 数据存储
    if (self.dataType === 'Day') {
      if (!self.selectBox.Day[key]) {
        self.selectBox.Day[key] = [];
      }
      self.selectBox.Day[key].push(value);
      // 数据整理将重合的数据整理为一条数据
      self.selectBox.Day[key] = mergeOverlappingTimeRanges(self.selectBox.Day[key])
    } else {
      if (!self.selectBox.Week[key]) {
        self.selectBox.Week[key] = [];
      }
      self.selectBox.Week[key].push(value);
      // 数据整理将重合的数据整理为一条数据
      self.selectBox.Week[key] = mergeOverlappingTimeRanges(self.selectBox.Week[key])
    }
    self.callback(self.selectBox);
  }
  // 日视图渲染
  renderDay() {
    $(`${this.ele} .room-data-box`).html('');
    // 表格内容
    var tableHtml = '<table class="room-data-table"><tbody>';
    for (const record of this.list) {
      tableHtml += setting.dayHtml.TableHtml.StartHtml(record.name, record.id);
      for (let i = 0; i < setting.dayList.length - 1; i++) {
        const element = setting.dayList[i];
        tableHtml += setting.dayHtml.TableHtml.loopContent(element.name, this.currentTime);
      }
      tableHtml += setting.dayHtml.TableHtml.EndHtml;
    }
    tableHtml += '</tbody></table>';
    var dataHtml = setting.dayHtml.DataHtml.StartHtml;
    // 时间内容
    for (let i = 0; i < setting.dayList.length; i++) {
      const record = setting.dayList[i];
      if (i === setting.dayList.length - 1) {
        dataHtml += setting.dayHtml.DataHtml.endContent(record.name);
      } else {
        dataHtml += setting.dayHtml.DataHtml.loopContent(record.name, this.currentTime);
      }
    }
    dataHtml += setting.dayHtml.DataHtml.EndHtml;
    $(`${this.ele} .room-data-box`).html(dataHtml + tableHtml);
  }
  // 周视图渲染
  renderWeek() {
    const numberName = ['一', '二', '三', '四', '五', '六', '日'];
    $(`${this.ele} .room-data-box`).html('');
    var html = setting.weekHtml.baseHtml;
    const weekDays = getWeekDays(this.currentWeek);
    // 设置时间格式
    var weekHander = setting.weekHtml.DataHtml.StartHtml;
    // 设置三个区间格式
    var weekArea = `<tr class="room-data-tr">`;
    for (let i = 0; i < weekDays.length; i++) {
      const record = weekDays[i];
      weekHander += setting.weekHtml.DataHtml.lookContent('周' + numberName[i] + ' ' + record.slice(5), record);
      for (let j = 0; j < 3; j++) {
        if (j === 0) {
          weekArea += `<td class="room-data-td week-hander-td">上午</td>`
        } else if (j === 1) {
          weekArea += `<td class="room-data-td week-hander-td">下午</td>`
        } else {
          weekArea += `<td class="room-data-td week-hander-td">晚上</td>`
        }
      }
    }
    // 设置区间选择
    var tableHtml = '';
    for (const record of this.list) {
      tableHtml += setting.weekHtml.TableHtml.StartHtml(record.name, record.id);
      for (const data of weekDays) {
        for (let i = 0; i < 3; i++) {
          if (i === 0) {
            tableHtml += setting.weekHtml.TableHtml.loopContent(data + ' 08:00', data + ' 12:00');
          } else if (i === 1) {
            tableHtml += setting.weekHtml.TableHtml.loopContent(data + ' 12:00', data + ' 17:00');
          } else {
            tableHtml += setting.weekHtml.TableHtml.loopContent(data + ' 17:00', data + ' 21:00');
          }
        }
      }
      tableHtml += setting.dayHtml.TableHtml.EndHtml;
    }
    weekHander += setting.weekHtml.DataHtml.endHtml + weekArea + tableHtml;
    $(`${this.ele} .room-data-box`).html(html + weekHander);
  }
  // 当页面加载或者类型切换时数据重置
  resetTypeChangeData(self) {
    self.selectBox = {
      active: null,
      StartTime: null,
      Day: {},
      Week: {},
    };
    $(`${self.ele} .filter-data .look-label`).hide()
    if (self.dataType === 'Day') {
      $(`${self.ele} .filter-data .day-label`).show()
      self.renderDay();
    } else {
      $(`${self.ele} .filter-data .week-label`).show()
      self.renderWeek();
    }
    // 选择时间事件
    $(`${self.ele} .room-item-area`).on('mousedown', function (e) {
      self.selectAreaData(e.currentTarget, self);
    })
    $(`${self.ele} .room-item-area`).on('mouseup', function (e) {
      self.selectAreaData(e.currentTarget, self);
    })
    if (self.dataType === 'Day') {
      setTimeout(() => {
        self.roomNotInfoDay(self.notInfo.notMyself, 'notMyself')
        self.roomNotInfoDay(self.notInfo.not, 'not')
      }, 300);
    } else {
      setTimeout(() => {
        self.roomNotInfoWeek(self.notInfo.notMyself, 'notMyself')
        self.roomNotInfoWeek(self.notInfo.not, 'not')
      }, 300);
    }
  }
  dataSelectChange(ele, self) {
    // 将值进行保存
    if (self.dataType === 'Day') {
      if (!$(ele).val()) {
        $(ele).val(formatCurrentDate(new Date()))
      }
      self.currentTime = $(ele).val();
      self.renderDay();
    } else {
      if (!$(ele).val()) {
        $(ele).val(getISOWeekNumber(new Date()))
      }
      self.currentWeek = $(ele).val();
      self.renderWeek();
    }
    // 选择时间事件
    $(`${self.ele} .room-item-area`).on('mousedown', function (e) {
      self.selectAreaData(e.currentTarget, self);
    })
    $(`${self.ele} .room-item-area`).on('mouseup', function (e) {
      self.selectAreaData(e.currentTarget, self);
    })
    if (self.dataType === 'Day') {
      // 关于不可预约和自己预约的房间
      self.roomNotInfoDay(self.notInfo.notMyself, 'notMyself')
      self.roomNotInfoDay(self.notInfo.not, 'not')
      self.roomNotInfoDay(self.selectBox.Day, 'current');
    } else {
      // 关于不可预约和自己预约的房间
      self.roomNotInfoWeek(self.notInfo.notMyself, 'notMyself')
      self.roomNotInfoWeek(self.notInfo.not, 'not')
      self.roomNotInfoWeek(self.selectBox.Week, 'current');
    }
  }
  // 当行选择时数据重置
  resetSelectLine(self) {
    self.selectBox.active = null;
    self.selectBox.StartTime = null;
    $(`${self.ele} .room-data-tr`).off('mousemove');
    $(`${self.ele} .room-item-select-box`).remove();
  }
  // 天预约------ 设置房间不可预约的日期 info 格式为正常格式  isType 代表类型 not 不能选择 notMyself 之前的预约 current 当前预约
  roomNotInfoDay(info, isType) {
    const currentTime = formatCurrentDate(new Date(this.currentTime));
    var className = '';
    if (isType === 'notMyself') {
      className = 'room-item-my-not-info';
    } else if (isType === 'current') {
      className = 'room-item-current-area';
    } else {
      className = 'room-item-not-info';
    }
    for (const key in info) {
      for (const record of info[key]) {
        $(`${this.ele} .room-data-tr`).each((idx, element) => {
          if ($(element).attr('key') === key) {
            var leftArea = 0;
            var widthArea = 0;
            // 获取元素信息
            $(element).find('.room-item-area').each((index, area) => {
              if (index === 0) {
                const currentEle = area.getBoundingClientRect();
                leftArea = currentEle.left - area.offsetWidth / 2;
              }
              // 获取左侧偏移量
              if (new Date(currentTime + ' ' + $(area).attr('startTime')).getTime() <= new Date(record.StartTime).getTime()) {
                const currentEle = area.getBoundingClientRect();
                leftArea = currentEle.left - area.offsetWidth / 2;
              }
              // 获取宽度
              if (new Date(currentTime + ' ' + $(area).attr('endtime')).getTime() <= new Date(record.EndTime).getTime()) {
                const currentEle = area.getBoundingClientRect()
                const left = currentEle.left + area.offsetWidth / 2;
                widthArea = left - leftArea;
              }
            })
            if (widthArea) {
              // 创建元素进行展示
              $(element).find('.room-select-area-box').append(`<div class="${className}"  starttime="${record.StartTime}"  endtime="${record.StartTime}" style="left:${leftArea + 4}px;width:${widthArea}px;"></div>`)
            }
          }
        })
      }
    }
    const self = this;
    $(`${this.ele} .${className}`).on('click', function (e) {
      self.changeArea(e.currentTarget, self);
    })
  }
  // 周预约------ 设置房间不可预约的日期 info 格式为正常格式  isType 代表类型 not 不能选择 notMyself 之前的预约 current 当前预约
  roomNotInfoWeek(info, isType) {
    var className = '';
    if (isType === 'notMyself') {
      className = 'room-item-my-not-info';
    } else if (isType === 'current') {
      className = 'room-item-current-area';
    } else {
      className = 'room-item-not-info';
    }
    for (const key in info) {
      for (const record of info[key]) {
        $(`${this.ele} .room-data-tr`).each((idx, element) => {
          if ($(element).attr('key') === key) {
            var leftArea = 0;
            var widthArea = 0;
            // 获取元素信息
            $(element).find('.room-item-area').each((index, area) => {
              if (index === 0) {
                // 当列表中绑定的数据开始时间都大于StartTime时
                const currentEle = area.getBoundingClientRect();
                leftArea = currentEle.left - area.offsetWidth / 2;
              }
              // 获取左侧偏移量
              if (new Date($(area).attr('startTime')).getTime() <= new Date(record.StartTime).getTime()) {
                const currentEle = area.getBoundingClientRect();
                leftArea = currentEle.left - area.offsetWidth / 2;
              }
              // 获取宽度
              if (new Date($(area).attr('endtime')).getTime() > new Date(record.StartTime).getTime() && new Date($(area).attr('endtime')).getTime() <= new Date(record.EndTime).getTime()) {
                // 当元素结束时间大于StartTime 并且 小于等于EndTime时 包含此块  
                const currentEle = area.getBoundingClientRect()
                const left = currentEle.left + area.offsetWidth / 2;
                widthArea = left - leftArea;
              } else if (new Date($(area).attr('endtime')).getTime() >= new Date(record.EndTime).getTime() && new Date(record.EndTime).getTime() > new Date($(area).attr('startTime')).getTime()) {
                // 当元素的结束时间大于EndTime 并且 大于等于StartTime时 包含此块
                const currentEle = area.getBoundingClientRect()
                const left = currentEle.left + area.offsetWidth / 2;
                widthArea = left - leftArea;
              }
            })
            if (widthArea) {
              // 创建元素进行展示
              $(element).find('.room-select-area-box').append(`<div class="${className}" starttime="${record.StartTime}"  endtime="${record.StartTime}" style="left:${leftArea + 10}px;width:${widthArea}px;"></div>`)
            }
          }
        })
      }
    }
    const self = this;
    $(`${this.ele} .${className}`).on('click', function (e) {
      self.changeArea(e.currentTarget, self);
    })
  }
  // 当点击区域时
  changeArea(ele, self) {
    const key = $(ele).parent().parent().attr('key');
    const startTime = $(ele).attr('starttime');
    const endTime = $(ele).attr('endtime');
    self.callbackChangeArea({
      key: key,
      data: {
        StartTime: startTime,
        EndTime: endTime
      }
    })
  }
  // 删除一条数据 传入 key 和 时间 key 为会议室id  data 为时间
  remove(key, data) {
    const myselfList = this.notInfo.notMyself[key] || [];
    const currentDay = this.selectBox.Day[key] || [];
    const currentWeek = this.selectBox.Week[key] || [];
    const myIdx = myselfList.findIndex(i => JSON.stringify(i) === JSON.stringify(data))
    const dayIdx = currentDay.findIndex(i => JSON.stringify(i) === JSON.stringify(data))
    const weekIdx = currentWeek.findIndex(i => JSON.stringify(i) === JSON.stringify(data))
    if (myIdx !== -1) {
      this.notInfo.notMyself[key].splice(myIdx, 1)
    } else if (dayIdx !== -1) {
      this.selectBox.Day[key].splice(dayIdx, 1)
    } else if (weekIdx !== -1) {
      this.selectBox.Week[key].splice(weekIdx, 1)
    }
    this.resetTypeChangeData(this)
  }
}

export default RoomClass;

 index.css

.room-select-box {
  font-size: 16px;
}

.room-select-box .hander-box {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
}

.room-select-box .hander-box .filter-box {
  display: flex;
  align-items: center;
}

.room-select-box .filter-box .item-filter {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  margin-bottom: 6px;
}

.room-select-box .filter-box .item-filter .label {
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.45);
  line-height: 20px;
  font-style: normal;
}

.room-select-box .filter-box .filter-data .date-input {
  width: 220px;
  height: 32px;
  padding: 0 12px;
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.65);
  font-style: normal;
  margin-right: 24px;
}

.room-select-box .filter-box .filter-type .select-radio {
  display: flex;
  align-items: center;
  border-radius: 5px;
  border: 1px solid rgba(0, 0, 0, 0.15);
}

.room-select-box .filter-box .filter-type .select-radio .item-radio {
  width: 88px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.65);
  line-height: 20px;
  font-style: normal;
}

.room-select-box .filter-box .filter-type .select-radio .item-radio:first-child {
  border-right: 1px solid rgba(0, 0, 0, 0.15);
}

.room-select-box .filter-box .filter-type .select-radio .active-radio {
  background: #1890FF;
  color: #fff;
}

.room-select-box .hander-box .state-box {
  display: flex;
  align-items: center;
}

.room-select-box .hander-box .state-box .item-state {
  display: flex;
  align-items: center;
  margin-left: 24px;
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.45);
  line-height: 20px;
  text-align: left;
  font-style: normal;
}

.room-select-box .hander-box .state-box .item-state .icon {
  width: 16px;
  height: 16px;
  margin-right: 8px;
  border-radius: 2px;
}

.room-select-box .hander-box .state-box .state-reservation .icon {
  border: 1px solid rgba(0, 0, 0, 0.06);
}

.room-select-box .hander-box .state-box .state-selected .icon {
  background: #1890FF;
  border: 1px solid #1890FF;
}

.room-select-box .hander-box .state-box .state-my-selected .icon {
  background: rgba(24, 144, 255, 0.25);
  border: 1px solid #1890FF;
}

.room-select-box .hander-box .state-box .state-not-selected .icon {
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(0, 0, 0, 0.45);
}

.room-select-box .room-data-box .room-data-table,
.room-data-th,
.room-data-td {
  border: 1px solid #EEEEEE;
  border-collapse: collapse;
  box-sizing: border-box;
}

.room-data-tr {
  position: relative;
}

.room-data-box .room-data-table {
  width: calc(100% - 21px);
  box-sizing: border-box;
}

.room-data-box .room-data-table .room-select-area-box {
  width: 0;
  border: none;
  margin: 0;
  padding: 0;
}

.room-data-box .room-data-th {
  width: 168px;
  padding: 16px 18px;
  box-sizing: border-box;
  text-align: left;
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.85);
  line-height: 22px;
  text-align: left;
  font-style: normal;
}

.room-data-table .room-data-td {
  position: relative;
}

.room-data-table .room-data-td .room-item-area {
  width: 50%;
  height: 100%;
  cursor: pointer;
  position: absolute;
  left: 0;
  top: 0;
}

.room-data-table .room-data-td .end-item-area {
  right: 0;
  top: 0;
  left: 50%;
}

.room-data-box {
  width: 100%;
}

.room-data-box .time-look-box {
  display: flex;
  justify-content: flex-end;
  position: relative;
  width: calc(100% - 21px);
}

.room-data-box .time-look-box .cler-time {
  width: 168px;
  flex: 0 0 auto;
}

.room-data-box .time-look-box .time-item {
  flex: 1;
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.45);
  line-height: 20px;
  font-style: normal;
  padding: 10px 0;
  box-sizing: border-box;
}

.room-data-box .time-look-box .time-item .left-text {
  display: inline-block;
  transform: translate(-50%, 0);
}

.room-data-box .time-look-box .end-time {
  position: absolute;
  right: 0;
}

.room-data-box .time-look-box .end-time .right-text {
  transform: translate(50%, 0);
}

/* 周展示的css */

.room-data-box .time-divide-box {
  display: flex;
  justify-content: end;
  align-items: center;
  margin-top: 10px;
  margin-bottom: 17px;
}

.room-data-box .time-divide-box .time-divide-item {
  margin-left: 24px;
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.45);
  line-height: 20px;
  text-align: left;
  font-style: normal;
}

.room-data-table .room-data-td .week-item-area {
  width: 100%;
  height: 100%;
  cursor: pointer;
  position: absolute;
  left: 0;
  top: 0;
}

.room-data-box .room-data-table .bgc-hander-box {
  width: 168px;
  height: 80px;
  background-image: url(./hander.png);
  background-size: 100% 100%;
  background-repeat: no-repeat;
}

.room-data-box .room-data-table .week-look-th {
  background: rgba(0, 0, 0, 0.02);
  font-weight: 500;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.85);
  line-height: 22px;
  text-align: left;
  font-style: normal;
  height: 40px;
}

.room-data-box .room-data-table .week-hander-td {
  height: 40px;
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.85);
  line-height: 22px;
  text-align: left;
  font-style: normal;
  text-align: center;
}

/* 正在选择中的类 */
.room-data-tr .room-item-select-box {
  position: absolute;
  height: 100%;
  bottom: 0;
  background: #1890FF;
  border-radius: 2px;
  box-sizing: border-box;
  border: 1px solid #1890FF;
  cursor: pointer;
  display: inline-block;
}

/* 已选择成功的类 */
.room-data-tr .room-item-current-area {
  position: absolute;
  height: 100%;
  box-sizing: border-box;
  background: #1890FF;
  display: inline-block;
  bottom: 0;
  border-radius: 2px;
  border: 1px solid #1890FF;
}

/* 不可预约 */
.room-data-tr .room-item-not-info {
  position: absolute;
  height: 100%;
  background: rgba(0, 0, 0, 0.25);
  border-radius: 2px;
  display: inline-block;
  bottom: 0;
  box-sizing: border-box;
  border: 1px solid rgba(0, 0, 0, 0.45);
  cursor: not-allowed;
}

/* 自己预约 */
.room-data-tr .room-item-my-not-info {
  position: absolute;
  height: 100%;
  display: inline-block;
  box-sizing: border-box;
  bottom: 0;
  background: rgba(24, 144, 255, 0.25);
  border-radius: 2px;
  border: 1px solid #1890FF;
  cursor: not-allowed;
}

/* 弹窗样式 */
.room-select-box .popup-box {
  width: 100vw;
  height: 100vh;
  color: #FFFFFF;
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
}

.room-select-box .popup-box .popup-content {
  padding: 16px 24px;
  box-sizing: border-box;
  background: #FFFFFF;
  box-shadow: 0px 9px 28px 8px rgba(0, 0, 0, 0.05), 0px 6px 16px 0px rgba(0, 0, 0, 0.08), 0px 3px 6px -4px rgba(0, 0, 0, 0.12);
  border-radius: 4px;
}

.room-select-box .popup-box .popup-content .popup-title {
  font-weight: 500;
  font-size: 16px;
  color: rgba(0, 0, 0, 0.85);
  line-height: 24px;
  text-align: left;
  font-style: normal;
}

.room-select-box .popup-box .popup-content .popup-title span {
  margin: 0 4px;
  color: #1890FF;
}

.room-select-box .popup-box .popup-content .form-item {
  margin-top: 8px;
  display: flex;
  align-items: center;
}

.room-select-box .popup-box .popup-content .form-item .form-label {
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.65);
  line-height: 22px;
  text-align: left;
  font-style: normal;
  width: 70px;
  flex: 0 0 auto;
}

.room-select-box .popup-box .popup-content .form-item .form-value-box {
  flex: 1;
}

.room-select-box .popup-box .popup-content .form-item .form-value {
  width: 100%;
  height: 32px;
  background: #FFFFFF;
  border-radius: 2px;
  border: 1px solid rgba(0, 0, 0, 0.15);
  outline: none;
  font-weight: 400;
  font-size: 14px;
  color: rgba(0, 0, 0, 0.65);
  line-height: 22px;
  text-align: left;
  font-style: normal;
  padding: 0 12px;
  box-sizing: border-box;
}

.room-select-box .popup-box .popup-content .operation-footer {
  margin-top: 16px;
  display: flex;
  align-items: center;
  justify-content: end;
}

.room-select-box .popup-box .popup-content .operation-footer div {
  width: 49px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 2px;
  font-weight: 400;
  font-size: 14px;
  line-height: 22px;
  font-style: normal;
  cursor: pointer;
}

.room-select-box .popup-box .popup-content .operation-footer div:first-child {
  margin-right: 8px;
}

.room-select-box .popup-box .popup-content .operation-footer .btn-cancel {
  background: #999999;
  color: #FFFFFF;
}

.room-select-box .popup-box .popup-content .operation-footer .btn-confirm {
  background: #EFA3A3;
  color: #FFFFFF;
}

.room-select-box .room-data-table .room-data-td .not-selected {
  cursor: not-allowed;
}

.day-current-time {
  color: #1890FF !important;
}

setting.js

// 按天展示时的时间段
const dayList = [
  {
    name: '08:00',
    id: 1,
  },
  {
    name: '09:00',
    id: 2,
  },
  {
    name: '10:00',
    id: 3,
  },
  {
    name: '11:00',
    id: 4,
  },
  {
    name: '12:00',
    id: 5,
  },
  {
    name: '13:00',
    id: 6,
  },
  {
    name: '14:00',
    id: 7,
  },
  {
    name: '15:00',
    id: 8,
  },
  {
    name: '16:00',
    id: 9,
  },
  {
    name: '17:00',
    id: 10,
  },
  {
    name: '18:00',
    id: 11,
  },
  {
    name: '19:00',
    id: 12,
  },
  {
    name: '20:00',
    id: 13,
  },
  {
    name: '21:00',
    id: 14,
  }
];
function formatCurrentDate(now) {
  // 提取年份、月份、日期  
  const year = now.getFullYear(); // 获取完整的年份(4位,1970-????)  
  const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份是从0开始的,所以要加1  
  const day = String(now.getDate()).padStart(2, '0'); // 获取日(1-31)  

  // 拼接成YYYY-MM-DD格式  
  return `${year}-${month}-${day}`;
}
// 基本信息
const baseHtml = function (dayTime, weekTime) {
  return `
 <div class="room-select-box">
      <!-- hander 筛选项 和 状态展示 -->
      <div class="hander-box">
        <div class="filter-box">
          <!-- 日期 -->
          <div class="filter-data item-filter">
            <div class="label">
              选择日期:
            </div>
            <div class="look-label day-label">
              <input type="date" placeholder="请选择日期" value="${dayTime}" format="YYYY-MM-DD" class="date-input" min="${dayTime}">
            </div>
            <div class="look-label week-label">
              <input type="week" placeholder="请选择周" value="${weekTime}" format="YYYY-WW" class="date-input" min="${weekTime}">
            </div>
          </div>
          <!-- 预约方式 -->
          <div class="filter-type item-filter">
            <div class="label">
              预约方式:
            </div>
            <div class="look-label">
              <div class="select-radio">
                <div class="item-radio active-radio" key="Day">
                  按天预约
                </div>
                <div class="item-radio" key="Week">
                  按周预约
                </div>
              </div>
            </div>
          </div>
        </div>
        <!-- 状态展示 -->
        <div class="state-box">
          <div class="item-state state-reservation">
            <div class="icon"></div>
            <span>可预约</span>
          </div>
          <div class="item-state state-selected">
            <div class="icon"></div>
            <span>当前选中时段</span>
          </div>
          <div class="item-state state-my-selected">
            <div class="icon"></div>
            <span>我的预约</span>
          </div>
          <div class="item-state state-not-selected">
            <div class="icon"></div>
            <span>不可预约</span>
          </div>
        </div>
      </div>
      <!-- 时间展示状态 -->
      <div class="room-data-box">
      </div>
    </div>`;
}
// 弹窗确认
const confirmHtml = function (timeArea, maxPeople, maxPeriod) {
  return `<div class="popup-box">
    <div class="popup-content">
        <div class="popup-title">
          确定预约 <span>${timeArea}</span> 此时间段教室吗?
        </div>
        <div class="form-item">
          <div class="form-label">
            期      次:
          </div>
          <div class="form-value-box">
            <input class="form-value value-period" type="number" min="1" placeholder="请输入期次" max="${maxPeriod}" value="1">
          </div>
        </div>
         <div class="form-item">
          <div class="form-label">
            计划人数:
          </div>
          <div class="form-value-box">
            <input class="form-value value-people" type="number" min="1" placeholder="请输入人数"  max="${maxPeople}" value="1">
          </div>
        </div>
        <div class="operation-footer">
            <div class="btn-cancel">取消</div>
            <div class="btn-confirm">确定</div>
        </div>
    </div>
  </div>`
}
// 关于按天预约展示的代码段
const dayHtml = {
  // 时间区域的html
  DataHtml: {
    StartHtml: `<div class="time-look-box"><div class="cler-time"></div>`,
    loopContent: function (dataTime, dayTime) {
      const now = formatCurrentDate(new Date());
      // 提取小时和分钟  
      const hours = new Date().getHours() + ':00';
      return `<div class="time-item">
            <div class="left-text ${hours === dataTime && now === dayTime ? 'day-current-time' : ''}">${dataTime}</div>
       </div>`
    },
    endContent: function (dataTime) {
      return `<div class="time-item end-time">
            <div class="right-text">${dataTime}</div>
       </div>`
    },
    EndHtml: `</div>`,
  },
  TableHtml: {
    StartHtml: function (Name, key) {
      return `<tr class="room-data-tr" key="${key}">
            <th class="room-data-th">${Name}</th>`
    },
    loopContent: function (dataTime, dayTime) {
      const now = new Date().getTime();
      const oneTime = new Date(dayTime + ' ' + (parseInt(dataTime.split(':')[0])) + ':30').getTime();
      const twoTime = new Date(dayTime + ' ' + (parseInt(dataTime.split(':')[0]) + 1) + ':00').getTime();
      return `<td class="room-data-td" key="${dataTime}">
              <div class="room-item-area ${now > oneTime ? 'not-selected' : ''}" startTime="${dataTime.split(':')[0]}:00" endTime="${dataTime.split(':')[0]}:30"></div>
              <div class="room-item-area end-item-area ${now > twoTime ? 'not-selected' : ''}" startTime="${dataTime.split(':')[0]}:30" endTime="${String(parseInt(dataTime.split(':')[0]) + 1).padStart(2, '0')}:00"></div>
            </td>`
    },
    EndHtml: `<td class="room-select-area-box"></td></tr>`
  }
}
// 按周预约展示的代码段
const weekHtml = {
  baseHtml: `
    <!-- 时间段展示区域 -->
    <div class="time-divide-box">
      <div class="time-divide-item">
        上午 08:00 ~ 12:00
      </div>
       <div class="time-divide-item">
        下午 12:00 ~ 17:00
      </div>
       <div class="time-divide-item">
        晚上 17:00 ~ 21:00
      </div>
    </div>
    <table class="room-data-table">
  `,
  endHtml: `</table>`,
  DataHtml: {
    StartHtml: `
      <tr class="room-data-tr">
        <td class="bgc-hander-box room-data-th" rowspan="2"></td>
    `,
    lookContent: function (dataTime, dayTime) {
      const now = formatCurrentDate(new Date());
      console.log(now, dayTime)
      return `<th class="room-data-th week-look-th ${now === dayTime ? 'day-current-time' : ''}" colspan="3">${dataTime}</th>`
    },
    endHtml: `</tr>`
  },
  TableHtml: {
    StartHtml: function (Name, key) {
      return `<tr class="room-data-tr" key="${key}">
            <th class="room-data-th">${Name}</th>`
    },
    loopContent: function (StartTime, EndTime) {
      const now = new Date().getTime();
      const end = new Date(EndTime).getTime()
      return `<td class="room-data-td">
              <div class="room-item-area week-item-area ${now > end ? 'not-selected' : ''}" startTime="${StartTime}" endTime="${EndTime}"></div>
            </td>`
    },
    EndHtml: `<td class="room-select-area-box"></td></tr>`
  }
}

// 导出数据
export default {
  dayList,
  dayHtml,
  baseHtml,
  weekHtml,
  confirmHtml
}

使用

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>教室预约系统</title>
</head>
<style>
  html,
  body,
  div {
    margin: 0px;
    padding: 0px;
  }

  #app {
    width: 1344px;
    padding: 16px;
  }
</style>

<body>
  <div id="app">
  </div>
  <script type="module">
    import RoomClass from './room/index.js';

    const room = new RoomClass({
      ele: '#app',
      list: [
        {
          name: "仿真培训机房311",
          id: 'id-999273',
          maxPeople: 10,
        },
        {
          name: "仿真培训机房311",
          id: 'id-555121387',
          maxPeople: 8,
        },
        {
          name: "安全楼机房",
          id: 'id-123456789',
          maxPeople: 6,
        }
      ],
      // 不可预约
      notInfo: {
        // 不可预约
        not: {
          'id-999273': [
            {
              'StartTime': '2024-09-04 09:00',
              'EndTime': '2024-09-05 10:00',
            }
          ],
          'id-555121387': [
            {
              'StartTime': '2024-09-05 10:30',
              'EndTime': '2024-09-05 15:00',
            }
          ],
          'id-123456789': [
            {
              'StartTime': '2024-09-05 08:30',
              'EndTime': '2024-09-05 15:00',
            }
          ],
        },
        // 我的预约
        notMyself: {
          'id-999273': [
            {
              'StartTime': '2024-09-05 13:00',
              'EndTime': '2024-09-05 15:00',
            }
          ],
          'id-555121387': [
            {
              'StartTime': '2024-09-05 16:30',
              'EndTime': '2024-09-05 19:00',
            }
          ],
          'id-123456789': [
            {
              'StartTime': '2024-09-05 15:30',
              'EndTime': '2024-09-06 15:30',
            }
          ],
        },
      },
      maxPeriod: 5,
      change: function (e) {
        console.log(e, 'change')
      },
      changeArea: function (e) {
        console.log(e, 'changeArea')
      }
    });
    // 初始化
    room.init();
    // 删除数据 删除方法
    // room.remove('id-999273',
    //   {
    //     'StartTime': '2024-09-05 13:00',
    //     'EndTime': '2024-09-05 15:00',
    //   }
    // )
  </script>
</body>

</html>

以上就是本次分享的内容,使用上有什么问题可以评论到下面,我看到后会及时回复,共同成长,希望下一次技术大牛就是你,看过麻烦点一个小小赞,加个鼓励

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值