首页 > 其他分享 >TDesign——投放时间段组件(48 * 7 位字符串)

TDesign——投放时间段组件(48 * 7 位字符串)

时间:2023-06-06 17:34:01浏览次数:38  
标签:TDesign const 48 weektime index list value 组件 return

前言

基于tdesign vue-next + ts实现
参考: byte-weektime-picker

内容

<!-- eslint-disable no-bitwise -->
<template>
  <div class="weektime">
    <div class="weektime-main">
      <div class="weektime-hd">
        <div class="weektime-hd-title">星期\时间</div>
        <div class="weektime-hd-con">
          <div class="weektime-hd-con-top">
            <div class="weektime-date-range">00:00 - 12:00</div>
            <div class="weektime-date-range">12:00 - 24:00</div>
          </div>
          <div class="weektime-hd-con-bottom">
            <span v-for="hour in 24" :key="hour" class="weektime-date-cell">{{ hour - 1 }}</span>
          </div>
        </div>
      </div>
      <div class="weektime-bd">
        <div class="week-body">
          <div v-for="week in weekDays" :key="week" class="week-item">{{ week }}</div>
        </div>
        <div class="time-body" @mousedown="handleMousedown" @mouseup="handleMouseup" @mousemove="handleMousemove">
          <t-tooltip v-for="(i, key) in weekTimes" :key="key" :content="tipTitle(key)">
            <div
              :data-index="key"
              class="time-cell"
              :class="{
                active: list[key] === '1',
                'pre-active': preViewIndex.includes(key),
                disable: disableTimes.includes(key),
              }"
            ></div>
          </t-tooltip>
        </div>
      </div>
    </div>
    <div class="weektime-help">
      <div class="weektime-help-tx">
        <div class="weektime-help-bd">
          <span class="color-box"></span>
          <span class="text-box">未选</span>
          <span class="color-box color-active"></span>
          <span class="text-box">已选</span>
        </div>
        <div class="weektime-help-ft" @click="initList">清空选择</div>
      </div>
      <div class="weektime-help-select">
        <p v-for="(week, key) in weekDays" v-show="showTimeText[key]" :key="key">
          <span class="weektime-help-week-tx">{{ week + ':' }}</span>
          <span>{{ showTimeText[key] }}</span>
        </p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';

const props = defineProps({
  value: {
    type: String,
  },
  // 自定义开始时段,0-47,每1代表半小时,星期一到星期日都生效
  startTime: {
    type: Number,
  },
  // 自定义结束时段,0-47,每1代表半小时,星期一到星期日都生效
  endTime: {
    type: Number,
  },
  // 自定义禁用时段,数字数组,0-335
  customDisableTimes: {
    type: Array,
  },
});

const DayTimes = 24 * 2;
const list = ref([]);
const isMove = ref(false);
const weekTimes = ref(7 * DayTimes);
const weekDays = ref(['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']);
const timeTextList = ref([]);
const startIndex = ref(0);
const axis = ref({
  startX: null,
  startY: null,
  endX: null,
  endY: null,
});
const preViewIndex = ref([]);
const showTimeText = ref([]);

watch(
  () => props.value,
  (n) => {
    if (n === list.value.join('')) return;
    initList(n);
  },
);

const emit = defineEmits(['update:value']);

const disableTimes = computed(() => {
  if (Array.isArray(props.customDisableTimes) && props.customDisableTimes.every((num) => typeof num === 'number'))
    return props.customDisableTimes;
  if (props.startTime > -1 && props.endTime > -1) {
    const disabled = [];
    for (let index = 0; index < weekTimes.value; index++) {
      const firstIdx = index % DayTimes;
      if (props.startTime > firstIdx || props.endTime < firstIdx) disabled.push(index);
    }
    return disabled;
  }
  return [];
});

/**
 * 鼠标停留时提示当前时间段
 */
const tipTitle = (index) => {
  const timeIndex = index % DayTimes;
  // eslint-disable-next-line no-bitwise
  const weekIndex = ~~(index / DayTimes);
  return `${weekDays.value[weekIndex]} ${timeTextList.value[timeIndex]}~${timeTextList.value[timeIndex + 1]}`;
};

/**
 * 初始化显示的时间数组
 * @return {Array} ["00:00","00:30","01:00",...]
 */
const initTimeText = () => {
  const timeTextList = [];
  const hours = [];
  const minutes = ['00', '30'];
  for (let i = 0; i <= 24; i++) {
    // eslint-disable-next-line no-unused-expressions
    i < 10 ? hours.push(`0${i}`) : hours.push(i.toString());
  }
  for (const hour of hours) {
    for (const minute of minutes) {
      timeTextList.push(`${hour}:${minute}`);
    }
  }
  return timeTextList;
};

const handleMousedown = (event) => {
  startIndex.value = event.target.getAttribute('data-index');
  // eslint-disable-next-line no-bitwise
  if (disableTimes.value.includes(~~startIndex.value)) return;
  isMove.value = true;
  axis.value.startX = startIndex.value % DayTimes;
  // eslint-disable-next-line no-bitwise
  axis.value.startY = ~~(startIndex.value / DayTimes);
};
const handleMouseup = (event) => {
  handleMousemove(event);
  resetMousemove();
};

const handleMousemove = (event) => {
  if (!isMove.value) return;
  const index = event.target.getAttribute('data-index');
  axis.value.endX = index % DayTimes;
  // eslint-disable-next-line no-bitwise
  axis.value.endY = ~~(index / DayTimes);
  preViewIndex.value = getSelectIndex();
};
const resetMousemove = () => {
  if (!isMove.value) return;
  setSelectIndex(preViewIndex.value);
  isMove.value = false;
  axis.value = {
    startX: null,
    startY: null,
    endX: null,
    endY: null,
  };
  preViewIndex.value = [];
};

/**
 * 获取拖动鼠标选择的index数组
 */
const getSelectIndex = () => {
  const indexList = [];
  const newAxis = {
    startX: Math.min(axis.value.startX, axis.value.endX),
    startY: Math.min(axis.value.startY, axis.value.endY),
    endX: Math.max(axis.value.startX, axis.value.endX),
    endY: Math.max(axis.value.startY, axis.value.endY),
  };
  for (let y = newAxis.startY; y <= newAxis.endY; y++) {
    for (let x = newAxis.startX; x <= newAxis.endX; x++) {
      indexList.push(x + y * DayTimes);
    }
  }
  return indexList.filter((v) => !disableTimes.value.includes(v));
};

/**
 * 设置选择的时间段并赋给绑定的值
 * @param {Array} indexList 选择的index数组
 */
const setSelectIndex = (indexList) => {
  if (!Array.isArray(indexList)) return;
  const listLength = indexList.length;
  const newData = list.value[startIndex.value] === '1' ? '0' : '1';
  for (let i = 0; i < listLength; i++) {
    list.value.splice(indexList[i], 1, newData);
  }
  emit('update:value', list.value.join(''));
  showSelectTime(list.value);
};

/**
 * 展示选择的时间段
 * @param {Array} list 已选择的list数组
 */
const showSelectTime = (list) => {
  if (!Array.isArray(list)) return;
  const weeksSelect = [];
  const listLength = list.length;
  showTimeText.value = [];
  if (listLength === 0) return;
  // 把 336长度的 list 分成 7 组,每组 48 个
  for (let i = 0; i < listLength; i += DayTimes) {
    weeksSelect.push(list.slice(i, i + DayTimes));
  }
  weeksSelect.forEach((item) => {
    showTimeText.value.push(getTimeText(item));
  });
};

const getTimeText = (arrIndex) => {
  if (!Array.isArray(arrIndex)) return '';
  const timeLength = arrIndex.length;
  let isSelect = false;
  let timeText = '';
  arrIndex.forEach((value, index) => {
    if (value === '1') {
      if (!isSelect) {
        timeText += timeTextList.value[index];
        isSelect = true;
      }
      if (index === timeLength - 1) timeText += `~${timeTextList.value[index + 1]}、`;
    } else if (isSelect) {
      timeText += `~${timeTextList.value[index]}、`;
      isSelect = false;
    }
  });
  return timeText.slice(0, -1);
};

// eslint-disable-next-line consistent-return
const initList = (value: any) => {
  const reg = new RegExp(`^[01]{${weekTimes.value}}$`);
  if (value && reg.test(value)) {
    list.value = value.split('');
    return showSelectTime(list.value);
  }
  list.value = new Array(weekTimes.value).fill('0');
  emit('update:value', list.value.join(''));
  showSelectTime(list.value);
};

onMounted(() => {
  timeTextList.value = initTimeText();
  document.addEventListener('mouseup', resetMousemove);
  initList(props.value);
});

onUnmounted(() => {
  document.removeEventListener('mouseup', resetMousemove);
});
</script>

<style lang="less" scoped>
div,
span,
p {
  margin: 0;
  padding: 0;
  border: 0;
  font-weight: normal;
  vertical-align: baseline;
  -webkit-tap-highlight-color: transparent;
  -ms-tap-highlight-color: transparent;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}
.weektime {
  width: 658px;
  font-size: 14px;
  line-height: 32px;
  color: #515a6e;
  user-select: none;
}
.weektime .weektime-main {
  border: 1px solid #dcdee2;
  position: relative;
}
.weektime .weektime-hd {
  display: flex;
  background: #f8f8f9;
}
.weektime .weektime-hd-title {
  display: flex;
  align-items: center;
  padding: 0 6px;
  width: 80px;
  height: 65px;
}
.weektime .weektime-hd-con {
  flex: 1;
  display: flex;
  -webkit-box-orient: vertical;
  flex-direction: column;
}
.weektime .weektime-hd-con-top {
  display: flex;
  border-bottom: 1px solid #dcdee2;
}
.weektime .weektime-date-range {
  width: 288px;
  height: 32px;
  line-height: 32px;
  text-align: center;
  border-left: 1px solid #dcdee2;
}
.weektime .weektime-hd-con-bottom {
  display: flex;
}
.weektime .weektime-date-cell {
  width: 24px;
  height: 32px;
  line-height: 32px;
  text-align: center;
  border-left: 1px solid #dcdee2;
}
.weektime .weektime-bd {
  display: flex;
}
.weektime .week-body {
  width: 80px;
  flex-shrink: 0;
}
.weektime .week-item {
  border-top: 1px solid #dcdee2;
  text-align: center;
  height: 30px;
  line-height: 30px;
}
.weektime .time-body {
  width: 576px;
  height: 210px;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  position: relative;
}
.weektime .time-cell {
  position: relative;
  width: 12px;
  height: 30px;
  border-left: 1px solid #efefef;
  border-top: 1px solid #efefef;
  overflow: hidden;
  transition: all 0.3s ease;
  outline-width: 0;
}
.weektime .time-cell.active {
  background: #2d8cf0;
}
.weektime .time-cell.disable {
  cursor: no-drop;
}
.weektime .time-cell::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: transparent;
  opacity: 0.5;
  transition: all 866ms ease;
  z-index: 99999;
}
.weektime .pre-active::after {
  background: #113860;
}
.weektime .disable::after {
  background: #cccccc;
}
.time-area {
  width: 576px;
  height: 210px;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 100;
  background: transparent;
}
.weektime .weektime-help {
  width: 658px;
  border: 1px solid #dcdee2;
  border-top: none;
  padding: 5px 15px;
}
.weektime .weektime-help-tx {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.weektime .weektime-help-week-tx {
  color: #999;
}

.weektime .weektime-help-bd {
  display: flex;
  align-items: center;
  -webkit-box-pack: start;
  -ms-flex-pack: start;
  justify-content: flex-start;
  padding: 4px 0;
}
.weektime .weektime-help .color-box {
  width: 14px;
  height: 20px;
  background: #fff;
  border: 1px solid #dddddd;
  display: block;
  margin-right: 6px;
}
.weektime .weektime-help-bd .color-box.color-active {
  background: #2d8cf0;
}
.weektime .weektime-help .text-box {
  margin-right: 15px;
}
.weektime .weektime-help .weektime-help-ft {
  color: #2d8cf0;
  cursor: pointer;
}
</style>

标签:TDesign,const,48,weektime,index,list,value,组件,return
From: https://www.cnblogs.com/wangyang0210/p/17461215.html

相关文章

  • Element 日期组件
    1.能选择的时间大于现在 <el-date-pickerv-model="formData.beginTime"type="datetime"value-format="YYYY-MM-DDHH:mm:ss"placeholder="请选择开始时间":disabledDate="disabledDateFn":disabled-hours="disabledHour......
  • (转)常见日志收集方案及相关组件
    原文:https://www.cnblogs.com/hujinzhong/p/15005523.html一、常见日志收集方案1.1、EFK​在Kubernetes集群上运行多个服务和应用程序时,日志收集系统可以帮助你快速分类和分析由Pod生成的大量日志数据。Kubernetes中比较流行的日志收集解决方案是Elasticsearch、Fluentd和Kiba......
  • 微信小程序使用vant组件van-datetime-picker unexpected character `@`
     报错 改成 vue不能直接引用,得定义了或者......
  • 848中国鱼类资料图谱大全ACCESS\EXCEL数据库
    这两年钓鱼的视频很火,天元邓刚“醉翁之意不在酒”专钓人家的鸡鸭羊也是看得过瘾,盘老板、被老板盘也一度成为热词,相信钓鱼的人或者想钓鱼的人有很多很多,但入门不就要识得一些鱼吗!今天这个中国鱼类图谱ACCESS资料数据库,不但包含了:分类、名称、英文名、俗名、产地及产期、详细介绍,而......
  • 如何使用TypeScript和Styled-Components构建图像轮播组件
    近年来,OTT(over-the-top)视频流媒体平台变得更加创新和易于使用。在他们的用户界面中,电影和连续剧的标题排列得清晰可见。在本教程中,我将指导您完成创建图像轮播组件的过程,该组件看起来就像您在许多OTT平台(想想Netflix)上看到的一样。我们将从创建原子组件开始,例如Tags、Descrip......
  • 算法学习day48动态规划part09-377、213、198
    packageLeetCode.DPpart09;/***377.组合总和Ⅳ*给你一个由不同整数组成的数组nums,和一个目标整数target。请你从nums中找出并返回总和为target的元素组合的个数。*题目数据保证答案符合32位整数范围。*示例:*输入:nums=[1,2,3],target=4*输......
  • React学习时,自己拟定的一则小案例(table表格组件,含编辑)
    某次在Uniapp群看到有人问uniapp如何操作dom元素。他想对这张表标红的区域,做dom元素获取,因为产品想让红色色块点击时,成为可编辑,渲染1~4月份之间的行程安排。于是,有小伙伴说让他用position定位这里,点击时使红色色块层级抬高,弄个input上去。但提问的小伙伴并没有决定这么做,随后......
  • echarts 曲线图组件
    样式如图使用:     <echartLine      ref="day30Echat"      :xAxis="timeList"      :xlist="xlist30Day"      :xlist2="xlist230Day"      :smooth="true"     ><......
  • 【React工作记录八十七】React+antDesign实现上传图片功能(类组件)
    前言大家好我是歌谣今天继续给大家带来工作中实战部分的一些代码的封装和认识需求实现1可以支持上传最多九张图片2图片支持预览替换删除3支持自定义上传文件大小格式未上传提示实现效果子组件封装UploadImage组件*@Description:公共上传图片*@param{Array}type图片......
  • 【React工作记录八十八】React+antDesign封装一个tab组件(类组件)
    前言我是歌谣放弃很容易但是坚持一定很酷喜欢我就一键三连哈微信公众号关注前端小歌谣在我们的工作生活中每次学习一个框架我们就不免要封装组件而具备封装一个完美组件的能力我称之为"优秀"简单的父子组件父组件<Geyao/>子组件importReact,{Component}from'react';......