vue+ts做一个类似课程表

vue+ts做一个类似课程表的待办清单

效果:

html代码:

css 复制代码
      <el-table
        :data="timetable"
        :border="true"
        :span-method="objectSpanMethod"
        :header-cell-style="{
          background: '#d9e5fd',
          color: 'black',
          fontWeight: 1000
        }"
        max-height="calc(90vh - 120px)"
        style="width: 100%"
        :cell-style="tableCellStyle"
      >
        <el-table-column prop="sjd" label="时间段" width="80" align="center" />
        <el-table-column prop="jc" label="小时节点" width="150" align="center" />
        <el-table-column prop="minute" label="分钟节点" width="150" align="center" />
        <el-table-column prop="mon" :label="tableTitle[0]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.mon.title !== undefined">
              <div class="container">
                <span>{{ scope.row.mon.title }}</span>
                <div class="content">
                  <p v-if="scope.row.mon.end - scope.row.mon.start < 3">
                    <el-tooltip v-if="scope.row.mon.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.mon.content">
                      <span style="cursor: pointer">
                        {{ scope.row.mon.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.mon.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.mon.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.mon.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.mon.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.mon.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.mon)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="tue" :label="tableTitle[1]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.tue.title !== undefined">
              <div class="container">
                <span>{{ scope.row.tue.title }}</span>
                <div class="content">
                  <p v-if="scope.row.tue.end - scope.row.tue.start < 3">
                    <el-tooltip v-if="scope.row.tue.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.tue.content">
                      <span style="cursor: pointer">
                        {{ scope.row.tue.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.tue.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.tue.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.tue.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.tue.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.tue.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.tue)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="wed" :label="tableTitle[2]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.wed.title !== undefined">
              <div class="container">
                <span>{{ scope.row.wed.title }}</span>
                <div class="content">
                  <p v-if="scope.row.wed.end - scope.row.wed.start < 3">
                    <el-tooltip v-if="scope.row.wed.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.wed.content">
                      <span style="cursor: pointer">
                        {{ scope.row.wed.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.wed.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.wed.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.wed.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.wed.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.wed.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.wed)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="thu" :label="tableTitle[3]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.thu.title !== undefined">
              <div class="container">
                <span>{{ scope.row.thu.title }}</span>
                <div class="content">
                  <p v-if="scope.row.thu.end - scope.row.wed.start < 3">
                    <el-tooltip v-if="scope.row.thu.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.wed.content">
                      <span style="cursor: pointer">
                        {{ scope.row.thu.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.thu.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.thu.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.thu.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.thu.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.thu.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.thu)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="fri" :label="tableTitle[4]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.fri.title !== undefined">
              <div class="container">
                <span>{{ scope.row.fri.title }}</span>
                <div class="content">
                  <p v-if="scope.row.fri.end - scope.row.fri.start < 3">
                    <el-tooltip v-if="scope.row.wed.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.fri.content">
                      <span style="cursor: pointer">
                        {{ scope.row.fri.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.fri.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.fri.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.fri.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.fri.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.fri.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.fri)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="sat" :label="tableTitle[5]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.sat.title !== undefined">
              <div class="container">
                <span>{{ scope.row.sat.title }}</span>
                <div class="content">
                  <p v-if="scope.row.sat.end - scope.row.sat.start < 3">
                    <el-tooltip v-if="scope.row.sat.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.sat.content">
                      <span style="cursor: pointer">
                        {{ scope.row.sat.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.sat.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.sat.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.sat.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.sat.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.sat.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.sat)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="sun" :label="tableTitle[6]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.sun.title !== undefined">
              <div class="container">
                <span>{{ scope.row.sun.title }}</span>
                <div class="content">
                  <p v-if="scope.row.sun.end - scope.row.sun.start < 3">
                    <el-tooltip v-if="scope.row.sun.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.sun.content">
                      <span style="cursor: pointer">
                        {{ scope.row.sun.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.sun.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.sun.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.sun.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.sun.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.sun.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.sun)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
      </el-table>

ts代码:

javascript 复制代码
const tableCellStyle = ({ row, column }: any) => {
  if (row[column.property].title !== undefined) {
    switch (row[column.property].type) {
      case 1:
        return {
          "background-color": "#b3e19d",
          "border-radius": "10px",
          color: "#fff"
        };
      case 2:
        return {
          "background-color": "#a0cfff",
          "border-radius": "10px",
          color: "#fff"
        };
      case 3:
        return {
          "background-color": "#72b5b5",
          "border-radius": "10px",
          color: "#fff"
        };
      case 4:
        return {
          "background-color": "#eebe77",
          "border-radius": "10px",
          color: "#fff"
        };
      default:
        return {
          color: "#FFFFFF",
          "background-color": "#b1b3b8",
          "border-radius": "10px"
        };
    }
  }
};
// let maxHeight = 600;
const timetable = ref([]) as any;
const tableTitle = ref([]) as any;
const makeTimetable = () => {
  timetable.value = [];
  const classDuration = props.taskDuration; // 每节的时长,单位为分钟
  const morningStartHour = props.morningStartHour; // 上午起始小时
  const afternoonStartHour = props.afternoonStartHour; // 下午起始小时
  const totalNumClasses = props.length; // 总节次数量
  let currentHour = morningStartHour;
  let currentMinute = 0;

  for (let i = 0; i < totalNumClasses; i++) {
    const one = {
      no: i + 1,
      sjd: "", // 时间段
      minute: "",
      jc: "", // 节点
      mon: {}, // 周一
      tue: {}, // 周二
      wed: {}, // 周三
      thu: {}, // 周四
      fri: {}, // 周五
      sat: {}, // 周六
      sun: {} // 周日
    };

    if (i < totalNumClasses / 2) {
      // 上午课程
      one.sjd = "上午";
      if (currentMinute === 60) {
        currentHour += 1;
        currentMinute = 0;
      }
      const start = `${currentHour.toString().padStart(2, "0")}:${currentMinute.toString().padStart(2, "0")}`;
      currentMinute += classDuration;
      const endHour = currentMinute === 60 ? currentHour + 1 : currentHour;
      const endMinute = currentMinute === 60 ? 0 : currentMinute;
      const end = `${endHour.toString().padStart(2, "0")}:${endMinute.toString().padStart(2, "0")}`;
      one.minute = `${start} - ${end}`;
      // 在上午课程的结束部分,判断是否为1小时的课程
      const startHour1 = currentHour.toString().padStart(2, "0");
      const endHour2 = currentHour + 1;
      one.jc = `${startHour1}:00 - ${endHour2}:00`;
    } else {
      // 下午课程
      one.sjd = "下午";
      if (currentHour < afternoonStartHour) {
        currentHour = afternoonStartHour;
        currentMinute = 30;
      }
      if (currentMinute === 60) {
        currentHour += 1;
        currentMinute = 0;
      }
      const start = `${currentHour.toString().padStart(2, "0")}:${currentMinute.toString().padStart(2, "0")}`;
      currentMinute += classDuration;
      const endHour = currentMinute === 60 ? currentHour + 1 : currentHour;
      const endMinute = currentMinute === 60 ? 0 : currentMinute;
      const end = `${endHour.toString().padStart(2, "0")}:${endMinute.toString().padStart(2, "0")}`;
      one.minute = `${start} - ${end}` === "17:15 - 17:30" ? "17:15 - 23:00" : `${start} - ${end}`; //特殊时间 晚上的事都排到这个间断

      // 在下午课程的结束部分,判断是否为1小时的课程
      const startHour1 = currentHour.toString().padStart(2, "0");
      const endHour2 = currentHour + 1;
      one.jc = `${startHour1}:30 - ${endHour2}:30` === "16:30 - 17:30" ? "16:30 - 23:00" : `${startHour1}:30 - ${endHour2}:30`; //特殊时间 晚上的事都排到这个间断

      // 更新 currentHour 和 currentMinute
      if (currentMinute === 60) {
        currentHour += 1;
        currentMinute = 0;
      }
    }

    timetable.value.push(one);
  }
};
const weeks = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
/*获取时间戳*/
const getStartTime = (time: number): number => {
  const nowTimeDate = new Date(time);
  nowTimeDate.setHours(0, 0, 0, 0);
  return nowTimeDate.getTime();
};
/*时间格式化*/
const timestampToTime = (timestamp: number): string => {
  const date = new Date(timestamp);
  const Y = date.getFullYear() + "-";
  const M = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-";
  const D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
  return Y + M + D;
};
/*获取table标题*/
const getWeekDayDates = (startDate?: string): string[] => {
  const week: string[] = [];
  let start, end;

  // 获取开始时间和结束时间的时间戳
  if (startDate) {
    start = getStartTime(new Date(startDate).getTime());
  } else {
    // 计算开始时间的星期周一时间
    const todayWeekDay = new Date().getDay();

    if (todayWeekDay > 1) {
      start = getStartTime(new Date().getTime() - (todayWeekDay - 1) * 1000 * 60 * 60 * 24);
    } else if (todayWeekDay == 0) {
      start = getStartTime(new Date().getTime() - 6 * 1000 * 60 * 60 * 24);
    } else {
      start = getStartTime(new Date().getTime());
    }
  }
  end = start + 6 * 1000 * 60 * 60 * 24; // 默认结束时间为开始时间后的6天

  for (let i = 0; i < 7; i++) {
    const timeStamp = start + i * 1000 * 60 * 60 * 24;
    const formattedDate = timestampToTime(timeStamp);
    const weekDay = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"][i];
    const weekDate = `${weekDay} ${formattedDate}`;
    week.push(weekDate);

    // 如果达到结束时间,则跳出循环
    if (timeStamp >= end) {
      break;
    }
  }
  return week;
};
/*合并数据*/
const mergeData = () => {
  // 合并数据
  if (props.events.length > 0) {
    for (let i = 0; i < props.events.length; i++) {
      // 获取星期几
      const week = weeks[props.events[i].xq - 1];
      timetable.value[props.events[i].start - 1][week] = props.events[i];
    }
  }
};
const objectSpanMethod = ({ row, rowIndex, columnIndex }: any) => {
  if (columnIndex === 0) {
    if (rowIndex < props.morningLength) {
      return {
        rowspan: rowIndex === 0 ? props.morningLength : 0,
        colspan: 1
      };
    } else if (rowIndex > props.morningLength - 1 && rowIndex < props.morningLength + props.afternoonLength) {
      return {
        rowspan: rowIndex === props.afternoonLength ? props.afternoonLength : 0,
        colspan: 1
      };
    } else {
      return {
        rowspan: rowIndex === props.morningLength + props.afternoonLength ? props.length - props.morningLength - props.afternoonLength : 0,
        colspan: 1
      };
    }
  }
  if (columnIndex === 1) {
    if (rowIndex % 4 === 0) {
      return {
        rowspan: 4,
        colspan: 1
      };
    } else {
      return {
        rowspan: 0,
        colspan: 1
      };
    }
  }

  if (columnIndex >= 3 && columnIndex <= 9) {
    const day = row[weeks[columnIndex - 3]];
    const title = day.title !== undefined ? day.title : "";
    const rowspan = title ? Math.max(day.end - day.start + 1, 1) : 1; // 值不能小于 0
    return {
      rowspan: rowspan,
      colspan: 1
    };
  }

  return {
    rowspan: 1,
    colspan: 1
  };
};

/*生命周期*/
onMounted(() => {
  // maxHeight = document.documentElement.clientHeight;

  mergeData();
});
/*监听props*/
watch(
  props,
  (_newValue, _oldValue) => {
    timetable.value = [];
    makeTimetable();
    mergeData();
    tableTitle.value = getWeekDayDates(props.sendDate);
    console.log(timetable);
  },
  { immediate: true, deep: true }

完整代码:

javascript 复制代码
<template>
  <div>
    <div class="panel">
      <el-table
        :data="timetable"
        :border="true"
        :span-method="objectSpanMethod"
        :header-cell-style="{
          background: '#d9e5fd',
          color: 'black',
          fontWeight: 1000
        }"
        max-height="calc(90vh - 120px)"
        style="width: 100%"
        :cell-style="tableCellStyle"
      >
        <el-table-column prop="sjd" label="时间段" width="80" align="center" />
        <el-table-column prop="jc" label="小时节点" width="150" align="center" />
        <el-table-column prop="minute" label="分钟节点" width="150" align="center" />
        <el-table-column prop="mon" :label="tableTitle[0]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.mon.title !== undefined">
              <div class="container">
                <span>{{ scope.row.mon.title }}</span>
                <div class="content">
                  <p v-if="scope.row.mon.end - scope.row.mon.start < 3">
                    <el-tooltip v-if="scope.row.mon.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.mon.content">
                      <span style="cursor: pointer">
                        {{ scope.row.mon.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.mon.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.mon.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.mon.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.mon.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.mon.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.mon)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="tue" :label="tableTitle[1]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.tue.title !== undefined">
              <div class="container">
                <span>{{ scope.row.tue.title }}</span>
                <div class="content">
                  <p v-if="scope.row.tue.end - scope.row.tue.start < 3">
                    <el-tooltip v-if="scope.row.tue.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.tue.content">
                      <span style="cursor: pointer">
                        {{ scope.row.tue.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.tue.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.tue.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.tue.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.tue.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.tue.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.tue)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="wed" :label="tableTitle[2]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.wed.title !== undefined">
              <div class="container">
                <span>{{ scope.row.wed.title }}</span>
                <div class="content">
                  <p v-if="scope.row.wed.end - scope.row.wed.start < 3">
                    <el-tooltip v-if="scope.row.wed.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.wed.content">
                      <span style="cursor: pointer">
                        {{ scope.row.wed.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.wed.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.wed.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.wed.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.wed.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.wed.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.wed)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="thu" :label="tableTitle[3]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.thu.title !== undefined">
              <div class="container">
                <span>{{ scope.row.thu.title }}</span>
                <div class="content">
                  <p v-if="scope.row.thu.end - scope.row.wed.start < 3">
                    <el-tooltip v-if="scope.row.thu.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.wed.content">
                      <span style="cursor: pointer">
                        {{ scope.row.thu.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.thu.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.thu.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.thu.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.thu.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.thu.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.thu)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="fri" :label="tableTitle[4]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.fri.title !== undefined">
              <div class="container">
                <span>{{ scope.row.fri.title }}</span>
                <div class="content">
                  <p v-if="scope.row.fri.end - scope.row.fri.start < 3">
                    <el-tooltip v-if="scope.row.wed.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.fri.content">
                      <span style="cursor: pointer">
                        {{ scope.row.fri.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.fri.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.fri.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.fri.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.fri.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.fri.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.fri)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="sat" :label="tableTitle[5]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.sat.title !== undefined">
              <div class="container">
                <span>{{ scope.row.sat.title }}</span>
                <div class="content">
                  <p v-if="scope.row.sat.end - scope.row.sat.start < 3">
                    <el-tooltip v-if="scope.row.sat.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.sat.content">
                      <span style="cursor: pointer">
                        {{ scope.row.sat.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.sat.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.sat.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.sat.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.sat.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.sat.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.sat)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
        <el-table-column prop="sun" :label="tableTitle[6]" align="left">
          <template v-slot="scope">
            <div v-if="scope.row.sun.title !== undefined">
              <div class="container">
                <span>{{ scope.row.sun.title }}</span>
                <div class="content">
                  <p v-if="scope.row.sun.end - scope.row.sun.start < 3">
                    <el-tooltip v-if="scope.row.sun.content?.length > 35" popper-class="tooltip-box-item-first" effect="dark" placement="top" :content="scope.row.sun.content">
                      <span style="cursor: pointer">
                        {{ scope.row.sun.content?.slice(0, 35) + "..." }}
                      </span>
                    </el-tooltip>
                    <span v-else>
                      {{ scope.row.sun.content }}
                    </span>
                  </p>
                  <p v-else>{{ scope.row.sun.content }}</p>
                </div>
                <div class="footer">
                  <p><IconText :icon="Tools" :text="getDictLabel('todo_type', scope.row.sun.type)" /></p>
                </div>
                <div>
                  <el-button type="text" size="small" @click="deleteHandles(scope.row.sun.id)">{{ $t("delete") }}</el-button>
                  <el-button type="text" size="small" @click="addOrUpdateHandles(scope.row.sun.id)">{{ $t("update") }}</el-button>
                  <el-button type="text" size="small" @click="sendMessage(scope.row.sun)">通知</el-button>
                </div>
              </div>
            </div>
            <div v-else />
          </template>
        </el-table-column>
      </el-table>
    </div>
    <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="emit('getList')"></add-or-update>
  </div>
</template>

<script setup lang="ts">
import AddOrUpdate from "./todoreminder-add-or-update.vue";
import { ref, watch, onMounted, reactive } from "vue";
import { ElMessage } from "element-plus";
import { nextTick } from "vue";
import useView from "@/hooks/useView";
import IconText from "@/views/dcomponents/IconText.vue";
import { Tools } from "@element-plus/icons-vue";
import baseService from "@/service/baseService";
const props = defineProps({
  //上午节次数
  sendDate: {
    type: [String],
    default: Date.now()
  },
  //上午节次数
  morningLength: {
    type: [Number],
    default: 16
  },
  //下午节次数
  afternoonLength: {
    type: [Number],
    default: 16
  },
  //每节的时长,单位为分钟
  taskDuration: {
    type: [Number],
    default: 15
  },
  //上午起始小时
  morningStartHour: {
    type: [Number],
    default: 8
  },
  //上午起始小时
  afternoonStartHour: {
    type: [Number],
    default: 13
  },

  // 总节次
  length: {
    type: [Number],
    default: 32
  },
  //数据
  events: {
    type: Array<any>,
    default: null
  }
});
//引用useView
const state = reactive({
  deleteURL: "/mytodo/todoreminder",
  deleteIsBatch: true,
  dataForm: {
    id: "",
    xq: "",
    start: "",
    end: ""
  }
});

//初始化
const { getDictLabel, deleteHandle, addOrUpdateHandle } = useView(state);
const emit = defineEmits(["getList"]);
const deleteHandles = (id: any) => {
  deleteHandle(id).then((res) => {
    emit("getList");
  });
};
const addOrUpdateVisible = ref(false);
const addOrUpdate = ref<any | null>(null);
const addOrUpdateHandles = (id: any) => {
  addOrUpdateVisible.value = true;
  console.log(addOrUpdate);
  nextTick(() => {
    addOrUpdate.value.dataForm.id = id;
    addOrUpdate.value.init();
  });
};
//推送消息
const sendMessage = (row: any) => {
  if (!isTodayOrTomorrow(row.sendDate)) {
    return ElMessage.error("通知时间范围仅限今天和明天");
  }
  baseService.post("mytodo/todoreminder/sendMessage", row).then((res) => {
    if (res.code !== 0) {
      return ElMessage.error(res.msg);
    }
    return ElMessage.success("推送成功!");
  });
};
//时间校验
const isTodayOrTomorrow = (dateStr: string): boolean => {
  const today = new Date().toISOString().split("T")[0];
  const tomorrow = new Date();
  tomorrow.setDate(tomorrow.getDate() + 1);
  const tomorrowStr = tomorrow.toISOString().split("T")[0];
  return dateStr === today || dateStr === tomorrowStr;
};
const tableCellStyle = ({ row, column }: any) => {
  if (row[column.property].title !== undefined) {
    switch (row[column.property].type) {
      case 1:
        return {
          "background-color": "#b3e19d",
          "border-radius": "10px",
          color: "#fff"
        };
      case 2:
        return {
          "background-color": "#a0cfff",
          "border-radius": "10px",
          color: "#fff"
        };
      case 3:
        return {
          "background-color": "#72b5b5",
          "border-radius": "10px",
          color: "#fff"
        };
      case 4:
        return {
          "background-color": "#eebe77",
          "border-radius": "10px",
          color: "#fff"
        };
      default:
        return {
          color: "#FFFFFF",
          "background-color": "#b1b3b8",
          "border-radius": "10px"
        };
    }
  }
};
// let maxHeight = 600;
const timetable = ref([]) as any;
const tableTitle = ref([]) as any;
const makeTimetable = () => {
  timetable.value = [];
  const classDuration = props.taskDuration; // 每节的时长,单位为分钟
  const morningStartHour = props.morningStartHour; // 上午起始小时
  const afternoonStartHour = props.afternoonStartHour; // 下午起始小时
  const totalNumClasses = props.length; // 总节次数量
  let currentHour = morningStartHour;
  let currentMinute = 0;

  for (let i = 0; i < totalNumClasses; i++) {
    const one = {
      no: i + 1,
      sjd: "", // 时间段
      minute: "",
      jc: "", // 节点
      mon: {}, // 周一
      tue: {}, // 周二
      wed: {}, // 周三
      thu: {}, // 周四
      fri: {}, // 周五
      sat: {}, // 周六
      sun: {} // 周日
    };

    if (i < totalNumClasses / 2) {
      // 上午课程
      one.sjd = "上午";
      if (currentMinute === 60) {
        currentHour += 1;
        currentMinute = 0;
      }
      const start = `${currentHour.toString().padStart(2, "0")}:${currentMinute.toString().padStart(2, "0")}`;
      currentMinute += classDuration;
      const endHour = currentMinute === 60 ? currentHour + 1 : currentHour;
      const endMinute = currentMinute === 60 ? 0 : currentMinute;
      const end = `${endHour.toString().padStart(2, "0")}:${endMinute.toString().padStart(2, "0")}`;
      one.minute = `${start} - ${end}`;
      // 在上午课程的结束部分,判断是否为1小时的课程
      const startHour1 = currentHour.toString().padStart(2, "0");
      const endHour2 = currentHour + 1;
      one.jc = `${startHour1}:00 - ${endHour2}:00`;
    } else {
      // 下午课程
      one.sjd = "下午";
      if (currentHour < afternoonStartHour) {
        currentHour = afternoonStartHour;
        currentMinute = 30;
      }
      if (currentMinute === 60) {
        currentHour += 1;
        currentMinute = 0;
      }
      const start = `${currentHour.toString().padStart(2, "0")}:${currentMinute.toString().padStart(2, "0")}`;
      currentMinute += classDuration;
      const endHour = currentMinute === 60 ? currentHour + 1 : currentHour;
      const endMinute = currentMinute === 60 ? 0 : currentMinute;
      const end = `${endHour.toString().padStart(2, "0")}:${endMinute.toString().padStart(2, "0")}`;
      one.minute = `${start} - ${end}` === "17:15 - 17:30" ? "17:15 - 23:00" : `${start} - ${end}`; //特殊时间 晚上的事都排到这个间断

      // 在下午课程的结束部分,判断是否为1小时的课程
      const startHour1 = currentHour.toString().padStart(2, "0");
      const endHour2 = currentHour + 1;
      one.jc = `${startHour1}:30 - ${endHour2}:30` === "16:30 - 17:30" ? "16:30 - 23:00" : `${startHour1}:30 - ${endHour2}:30`; //特殊时间 晚上的事都排到这个间断

      // 更新 currentHour 和 currentMinute
      if (currentMinute === 60) {
        currentHour += 1;
        currentMinute = 0;
      }
    }

    timetable.value.push(one);
  }
};
const weeks = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
/*获取时间戳*/
const getStartTime = (time: number): number => {
  const nowTimeDate = new Date(time);
  nowTimeDate.setHours(0, 0, 0, 0);
  return nowTimeDate.getTime();
};
/*时间格式化*/
const timestampToTime = (timestamp: number): string => {
  const date = new Date(timestamp);
  const Y = date.getFullYear() + "-";
  const M = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-";
  const D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
  return Y + M + D;
};
/*获取table标题*/
const getWeekDayDates = (startDate?: string): string[] => {
  const week: string[] = [];
  let start, end;

  // 获取开始时间和结束时间的时间戳
  if (startDate) {
    start = getStartTime(new Date(startDate).getTime());
  } else {
    // 计算开始时间的星期周一时间
    const todayWeekDay = new Date().getDay();

    if (todayWeekDay > 1) {
      start = getStartTime(new Date().getTime() - (todayWeekDay - 1) * 1000 * 60 * 60 * 24);
    } else if (todayWeekDay == 0) {
      start = getStartTime(new Date().getTime() - 6 * 1000 * 60 * 60 * 24);
    } else {
      start = getStartTime(new Date().getTime());
    }
  }
  end = start + 6 * 1000 * 60 * 60 * 24; // 默认结束时间为开始时间后的6天

  for (let i = 0; i < 7; i++) {
    const timeStamp = start + i * 1000 * 60 * 60 * 24;
    const formattedDate = timestampToTime(timeStamp);
    const weekDay = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"][i];
    const weekDate = `${weekDay} ${formattedDate}`;
    week.push(weekDate);

    // 如果达到结束时间,则跳出循环
    if (timeStamp >= end) {
      break;
    }
  }
  return week;
};
/*合并数据*/
const mergeData = () => {
  // 合并数据
  if (props.events.length > 0) {
    for (let i = 0; i < props.events.length; i++) {
      // 获取星期几
      const week = weeks[props.events[i].xq - 1];
      timetable.value[props.events[i].start - 1][week] = props.events[i];
    }
  }
};
const objectSpanMethod = ({ row, rowIndex, columnIndex }: any) => {
  if (columnIndex === 0) {
    if (rowIndex < props.morningLength) {
      return {
        rowspan: rowIndex === 0 ? props.morningLength : 0,
        colspan: 1
      };
    } else if (rowIndex > props.morningLength - 1 && rowIndex < props.morningLength + props.afternoonLength) {
      return {
        rowspan: rowIndex === props.afternoonLength ? props.afternoonLength : 0,
        colspan: 1
      };
    } else {
      return {
        rowspan: rowIndex === props.morningLength + props.afternoonLength ? props.length - props.morningLength - props.afternoonLength : 0,
        colspan: 1
      };
    }
  }
  if (columnIndex === 1) {
    if (rowIndex % 4 === 0) {
      return {
        rowspan: 4,
        colspan: 1
      };
    } else {
      return {
        rowspan: 0,
        colspan: 1
      };
    }
  }

  if (columnIndex >= 3 && columnIndex <= 9) {
    const day = row[weeks[columnIndex - 3]];
    const title = day.title !== undefined ? day.title : "";
    const rowspan = title ? Math.max(day.end - day.start + 1, 1) : 1; // 值不能小于 0
    return {
      rowspan: rowspan,
      colspan: 1
    };
  }

  return {
    rowspan: 1,
    colspan: 1
  };
};

/*生命周期*/
onMounted(() => {
  // maxHeight = document.documentElement.clientHeight;

  mergeData();
});
/*监听props*/
watch(
  props,
  (_newValue, _oldValue) => {
    timetable.value = [];
    makeTimetable();
    mergeData();
    tableTitle.value = getWeekDayDates(props.sendDate);
    console.log(timetable);
  },
  { immediate: true, deep: true }
);
</script>

<style scoped lang="scss">
.cellStyle {
  background-color: rgb(24 144 255 / 80%);
  color: #fff;
  border-radius: 10px;
}
.container {
  text-align: center; /* 让标题居中对齐 */
}

.title {
  text-align: center; /* 若标题超过一行,可居中对齐 */
}

.content {
  text-align: left; /* 让内容左对齐 */
}

.footer {
  text-align: right; /* 让结尾姓名右对齐 */
}
</style>
<style>
/*文字提示框样式,全局有效*/
.tooltip-box-item-first {
  width: 400px;
  max-height: 300px;
  /*overflow-y: scroll;*/
}
</style>
相关推荐
徊忆羽菲16 分钟前
学习使用在windows系统上安装vue前端框架以及环境配置图文教程
vue.js·学习·前端框架
范特西是只猫1 小时前
echarts 自定义标注样式&自定义tooltip弹窗样式
前端·javascript·echarts
建群新人小猿1 小时前
CRMEB Pro版 DIY功能玩法即将升级,先来一睹为快!
前端·javascript·html
WebGIS皮卡茂2 小时前
【数据可视化】Arcgis api 4.x 专题图制作之分级色彩,采用自然间断法(使用simple-statistics JS数学统计库生成自然间断点)
javascript·arcgis·信息可视化·前端框架
api773 小时前
1688商品详情API返回值中的售后保障与服务信息
java·服务器·前端·javascript·python·spring·pygame
赵广陆3 小时前
SprinBoot+Vue门诊管理系统的设计与实现
前端·javascript·vue.js·spring boot·maven
Python私教3 小时前
JavaScript 基于生成器的异步编程方案相关代码分享
android·javascript·okhttp
Bob99983 小时前
电脑浏览器访问华为路由器报错,无法访问路由器web界面:ERR_SSL_VERSION_OR_CIPHER_MISMATCH 最简单的解决办法!
开发语言·javascript·网络·python·网络协议·华为·ssl
B.-5 小时前
Remix 学习 - @remix-run/react 中主要的 hooks
前端·javascript·学习·react.js·web
计算机学姐5 小时前
基于微信小程序的食堂点餐预约管理系统
java·vue.js·spring boot·mysql·微信小程序·小程序·mybatis