开发一个移动会议预约模块

实现效果:

 

说明:

支持星期切换、支持上下滚动以及左右滚动

1 模板内容

<template>
  <van-tabs v-model="active" @change="tabChange" class="order">
    <van-tab v-for="(item, index) in weekDateList" :key="item.title" :title="item.title" >
      <div style="width: 100%;">
        <div style="position: relative;">
          <div class="mask"></div>
          <div :id="'top-tab' + index" class="top-tab">
              <div v-for="room in rooms" :key="room.room_uuid">{{ room.room_name }}</div>
          </div>
        </div>
          
       
        <div id="bom-con" @scroll="syncScroll">
          <div class="con-left">
            <div v-for="timeSlot in timeSlots" :key="timeSlot">{{ timeSlot }}</div>
          </div>
          <div id="tableContainer" style="width: calc(100% - 71px);" >
            <table v-show="!loading" id="order-table" class="order-table">
              <tbody>
                <tr v-for="timeSlot in timeSlots.slice(0, -1)" :key="timeSlot">
                  <td v-for="room,index in rooms" :key="room.room_uuid" class="border" :class="{isorder:getAppointment(room.room_uuid, timeSlot)=='已预约'}">
                    <span >{{ getAppointment(room.room_uuid, timeSlot) }}</span>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
          
      </div>
      </div>
    </van-tab>
  </van-tabs>
</template>

2 js部分

import Vue from 'vue'
import moment from 'moment';
import {Toast} from 'vant';

export default {
  name:'mtOrderView',
  data() {
    return {
      active: 0,
      currentDate: new Date(),
      loading: false,
      rooms: [],
      appointments: {},
      roomTimeOrder:{},
      show:true,
    };
  },
computed:{
    weekDateList() {
      const currentDayOfWeek = this.currentDate.getDay();
      this.active = currentDayOfWeek - 1
      const daysOffset = currentDayOfWeek > 0 ? currentDayOfWeek - 1 : 6;
      const weekStartDateTimestamp = this.currentDate.getTime() - (daysOffset * 24 * 60 * 60 * 1000);
      const weekDateList = [];

      for (let i = 0; i < 7; i++) {
        const date = new Date(weekStartDateTimestamp + (i * 24 * 60 * 60 * 1000));
        
        const weekdays = [ '周一', '周二', '周三', '周四', '周五', '周六','周日'];

        let day = {
          title:weekdays[i]+'('+moment(date).format('MM-DD')+')',
          date:date
        }
        if(currentDayOfWeek-1 == i){
          day = {
            title:'今天'+'('+moment(date).format('MM-DD')+')',
            date:date
          }
        }
        
        weekDateList.push(day);
      }
      return weekDateList;
    },
    queryDate(){
      return this.weekDateList[this.active].date
    },
    timeSlots() {
      // 根据需求定义每天的时间段
      const startTime = new Date();
      startTime.setHours(7, 0); // 设置开始时间为7点
      const endTime = new Date();
      endTime.setHours(20, 0); // 设置结束时间为19点

      const timeSlots = [];
      while (startTime < endTime) {
        timeSlots.push(this.formatTime(startTime));
        startTime.setMinutes(startTime.getMinutes() + 60); // 每个时间段为30分钟
      }

      return timeSlots;
    },
  },
  created(){
    this.userInfo = Vue.ls.get('userInfo');
  },
  mounted(){
    this.getData()
  },
 methods: {
    syncScroll(e) {
      let { active = 0 } = this
      var targetDiv = document.getElementById(`top-tab${active}`);
      // 将目标 div 的滚动位置设置为源 div 的滚动位置  sourceDiv.scrollLeft
      targetDiv.scrollLeft = e.target.scrollLeft;
      
    },

    tabChange(e){
      this.getData()
    },
    //刷新
    onRefresh() {
        this.getData()
      },
    formatTime(date) {
      return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
    },
    getData(){
      let currentDate = this.queryDate
      Toast.loading({
        message: '加载中...',
        forbidClick: true,
        loadingType: 'spinner',
      });
      this.loading = true
      const currentTimestamp = currentDate.getTime();
      // 计算后一天的时间戳(加上一天的毫秒数)
      const nextDayTimestamp = currentTimestamp + (24 * 60 * 60 * 1000);
      // 创建后一天的 Date 对象
      let nextDay = new Date(nextDayTimestamp);
      let startTime = moment(currentDate).format('YYYY-MM-DD')
      let endTime = moment(nextDay).format('YYYY-MM-DD')
      gaService(
          'service.ga.mtRoomApplyService',
          "queryByAttr2",
          {
            "queryFields": {
              "start_time":startTime,
              "end_time":endTime,
            },
            "userInfo": this.userInfo,
            "resultFields": "",
            "orderFields": "syscreatedate desc"
          }
        ).then(d => {
          d = d.data.data
          this.rooms = d.resultset.map(item=>{
            return {
              apply_detail:item.apply_detail,
              room_name:item.room_name,
              room_uuid:item.room_uuid
            }
          })

          this.roomTimeOrder = {}
          this.rooms.forEach(item=>{
            if(item.apply_detail){
              let key = `${item.room_uuid}`;
              this.roomTimeOrder[key] = item.apply_detail
            }
            
          })
          this.loading = false
          Toast.clear();
        }).catch(err => {
          console.log('err',err)
          this.loading = false
          Toast.clear();
          Toast.fail('获取数据失败',err);
          
        })
    },
    getAppointment(roomId, timeSlot) {
      if(this.roomTimeOrder[roomId]){
        let keys = Object.keys(this.roomTimeOrder[roomId])

        return keys.includes(timeSlot)?'已预约':'未预约'
      }else{
        return '未预约'
      }
    }
  }

3 样式

<style lang="less" scoped>
.order{
  height: 100vh;
}
.order-table{
  // margin-left: 70px;
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed; /* 强制表格使用固定布局 */
  td{
    width: 134px;
    height: 40px;
    text-align: center;
    padding: 8px;
    border-right: 1px solid #ddd;
    // background-color: #d9d9d9;
    span{
      color: rgb(129, 255, 127);
    }
  }

  th:not(:first-child),td:not(:first-child) {
    border-left: none;
  }

  td.border {
      // border-right: none;
      border: 1px solid #dddddd45;
    }

  thead th {
    position: sticky; /* 将表头设置为 sticky */
    top: 0; /* 设置固定位置在顶部 */
    background-color: #fff; /* 可选:添加背景色以区分固定行 */
  }

  th:first-child {
    z-index: 2; /* 提高层级以覆盖表头 */
  }

  .isorder{
    span{
      color: red;
    }
  }
}

.order {
  /deep/.van-tab{
    font-size: 18px;
  }
  /deep/.van-tabs__content{
    width: 100%;
    height: calc(100% - 70px);
    overflow: auto;

    // padding-top: 20px;
    background: #fff;
  }
  /deep/.van-tab__pane{
    display: flex;
    height: 100%;
    
  }
}

.con-left{
  // width: 70px;
  // margin-top: 40px;
  // border-right: 1px solid #ddd;
  position: sticky;
  left: 0;
  background-color: #fff;
  z-index: 99;

  div{
    width: 70px;
    height:57px;
    text-align: center;
    border-right: 1px solid #ddd;
    background-color: #fff;
  }
  div:last-child{
    border-right:none
  }
  div::after{
    content: '';
    width: 5px;
    position: absolute;
    /* top: 0; */
    right: 0;
    border-top: 1px solid #ddd;
  }
  

}

.top-tab{
  position: relative;

  display: flex;
  margin-left: 71px;
  overflow: auto hidden;

  scrollbar-width: none; /* Firefox 隐藏滚动条 */
  -ms-overflow-style: none; /* IE 和 Edge 隐藏滚动条 */

    div{
      width: 151px;
      height: 40px;
      text-align: center;
      flex-shrink: 0
    }
  }

#bom-con{
  display: flex;
  height: calc(100% - 40px); 
  overflow-y: auto;
  width: 100%;
}

.top-tab::-webkit-scrollbar,#bom-con::-webkit-scrollbar{
  display: none !important;
  width: 0 !important
}

.mask {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: transparent; /* 设置遮罩层的颜色和透明度 */
    z-index: 1; /* 确保遮罩层位于内容之上 */
    overflow: hidden;
  }



</style>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值