实验室排课表设计

问题背景

        接了一个学校的项目,做一个机房实验室预约系统,首先就是要实现一个课表,效果如图:

问题分析

        问题初期,查了CSDN和B站上的很多资料,看了很多的类似项目。但该课表与普通课表不同的是,在同一时间同一位置有多门课程。这就产生了一个难题——确定每条数据在课表中的位置。

        我自己想了两种解决方法:

  1. 1.v-for循环遍历。 存在问题:接口返回参数的数据结构定义较为复杂。
  2. 2.绝对定位,一条数据放在一个div中,对div做绝对定位。 存在问题:无法实现时间栏和位置栏的高度自适应

        后来问了一个前端大神,他给我的方法是:

  1. 拿到后端数据后,先构建二维表,
  2. 对时间列进行遍历,可以获取到数据的行索引,对相同的时间行进行合并
  3. 同理,在2的基础上,对位置列进行合并,将相同的位置行进行合并

        并且他还帮我定义了后端返回的数据结构:

const data = [
    {
    time: "8:00-10:00",
    position: "1号机房",
    class_list: [
      {
        week: "1",
        class: "李1-A设计-40人",
      },
      {
        ...
      },
    ],
  },
    {
    ...
  }
]

对于该结构,简单理解就是一张二维表,data数组中的一个元素就是二位表的一行

具体实现

        接下来就是具体实现,因为本人写vue项目还在小白阶段,很多东西还没有具体掌握,于是对于js代码的实现,具体参照的是以下文章:

js动态合并单元格_js动态合并表格单元格-CSDN博客

        但在实现过程中,我发现了该文章的一个问题:

for (var i=0;i<result.massage.length;i++){
     var stationName = result.massage[i].stationName; //这里我们在一次循环数据,获取站点的名字
     console.log(stationName)
     var id="."+stationName;
     console.log(id)//这里是拼接字符串
     var num=$(id).length;//然后获取这个class的长度
     console.log(num)
     $(id).not(":eq(0)").remove();//然后在这个class中除了第一个全部删除掉
     $(id).attr('rowspan',num);//然后合并class长度的单元格
   }

        在这段代码的最后一句前要加一条if判断,不然for循环在遍历时会覆盖前一趟循环设置的rowspan属性,即将这段代码改为:

for (var i=0;i<result.massage.length;i++){
     var stationName = result.massage[i].stationName; //这里我们在一次循环数据,获取站点的名字
     console.log(stationName)
     var id="."+stationName;
     console.log(id)//这里是拼接字符串
     var num=$(id).length;//然后获取这个class的长度
     console.log(num)
     $(id).not(":eq(0)").remove();//然后在这个class中除了第一个全部删除掉
     if (num != 1) $(id).attr('rowspan',num);//然后合并class长度的单元格
   }

        接下来就是按照大神提供的步骤来实现,具体js代码如下:

const courseList = reactive([
  {
    time: "8:00-10:00",
    position: "1号机房",
    class_list: [
      {
        week: "1",
        class: "李1-A设计-40人",
      },
      {
        week: "2",
        class: "李3-A设计-40人",
      },
      {
        week: "3",
        class: "李3-A设计-40人",
      },
      {
        week: "4",
        class: "李4-A设计-40人",
      },
      {
        week: "5",
        class: "李5-A设计-40人",
      },
      {
        week: "6",
        class: "李6-A设计-40人",
      },
      {
        week: "7",
        class: "李7-A设计-40人",
      },
    ],
  }

onMounted(() => {
  //合并日期列
  for (var i = 0; i < courseList.length; i++) {
    var id_time = courseList[i].time.split(":")[0]; //这里循环数据,获取自己起的class名
    console.log(id_time);
    var id = "." + id_time;
    console.log(id); //这里是拼接字符串
    var num = $(id).length; //然后获取这个class元素的个数
    console.log(num);
    $(id).not(":eq(0)").remove(); //然后在这个class中除了第一个全部删除掉
    if (num != 1) $(id).attr("rowspan", num); //然后合并相同class的单元格
  }
  // 合并位置列
  for (var n = 0; n < courseList.length; n++) {
    var id_position =
      courseList[n].time.split(":")[0] + courseList[n].position.match(/\d+/)[0];
    //str..match(/\d+/)[0] 
    var id = "." + id_position;
    var num = $(id).length; 
    $(id).not(":eq(0)").remove(); 
    if (num != 1) $(id).attr("rowspan", num); 
  }
});

        实现效果如图:

实现过程中遇到的问题以及解决方案

        事先声明:实现过程中遇到的问题主要在于我个人对js代码的不熟悉。

        首先就是jQuery的语法问题,在此项目之前我还没有学过jQuery,以至于连“$”的含义都不懂,于是就去查了很多资料,在结项后,需要将这部分学习下来。

        其次在合并单元格时,采用的是jQuery的.class选择器(经测试,#id选择器的num有异常,但没有具体深究),原博主直接将" '+'+车站名"作为class名。但在该项目中,时间和位置这两个信息都是以数字开头,且一个有':',一个有汉字都不满足class的命名要求。该解决方法如下:对于时间栏,采用str.split(':')函数,将时间信息切割成一个含三个元素的数组,取其第一个元素值作为时间栏class的名称;对于位置栏,使用str.match(/\d+/)[0] 正则表达式,来从字符串中提取数字,作为位置栏的class名称,与此同时,单用一个信息对位置栏<td>标签的class命名是不够的,因为对于不同时间的同一位置不能进行合并,所以又将该位置栏对应的时间栏的class名加了进去,就如代码中所写的  :class="item1.time.split(':')[0] + item1.position.match(/\d+/)[0]"  。

        最后,自己的vue3的特性还不是很熟悉,需要结项后和jQuery一起再学习学习。

结语

        对于“实验室排课表设计”的分享就到这里,后续还会对这张表进行改进,如果有时间的花还会再写几篇博客记录。

        

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值