自定義周選擇元件、年選擇元件

紫藤萝yu發表於2024-08-09

// 周元件 weekSelect

<!-- 周選擇元件 -->
<template>
  <div ref="viYearSelect" class="vi-year-select">
    <ui-input
            v-model="selectVal"
            :placeholder="placeholder"
            :disabled="disabled"
            readonly
      :clearable="clearable"
            @click.native.stop="showSelect"
            :suffix="selectShow ? 'ios-arrow-up' : 'ios-arrow-down'"
    />
    <div class="zTreeSelect" :style="{ width: width }" v-show="selectShow" @click.stop>
        <div class="panel-top">
          <span @click="prevYear">
            <ui-icon type="ios-arrow-back" size="16" color="#001F45" />
          </span>
          <div class="week-info">
            <span>{{defaultYear}}</span>&nbsp;
          </div>
          <span @click="nextYear">
            <ui-icon type="ios-arrow-forward" size="16" color="#001F45" />
          </span>
        </div>
        <div class="panel-info">
          <div class="option"
            v-for="(wItem,wIndex) in this.weekList"
            :key="wIndex"
            :title="wItem[0]+' 至 '+wItem[wItem.length-1]"
            :class="{'disabledCls': disabledCls(defaultYear, wIndex)}"
            @click="selectOption(wItem,wIndex,defaultYear)"
          >
            <span class="option-info">第{{wIndex*1+1*1}}周</span>
          </div>
        </div>
    </div>
  </div>
</template>
<script>
import { weekFormat } from "@/utils/index";
export default {
  name: "viWeekSelect",
  props: {
    model: {
      type: String
    },
    clearable: {
      type: Boolean,
      default: false
    },
    placeholder: {
      type: String,
      default: "請選擇",
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    disabledValR: { // 大於當前的值,禁止選擇,值格式為: YYYY 第N周
      type: String,
      default: ""
    },
    disabledValL: { // 小於當前的值,禁止選擇,值格式為: YYYY 第N周
      type: String,
      default: ""
    },
  },
  // model中:prop代表著我要和props的指定變數(model)相對應,event表示著事件,我觸發事件(change)的時候會改變父元件v-model的值
  model: {
    prop: "model",
    event: ""
  },
  watch: {
    model: {
      deep: true,
      immediate: true,
      handler(val) {
        this.selectVal = val;
      }
    }
  },
  computed: {
    // 周,禁止選擇項判斷
    disabledCls() {
      return function (dyear, wIndex) {
        try {
          dyear = Number(dyear);
          wIndex = Number(wIndex);
          if (this.disabledValR) {
            const year = Number(this.disabledValR.split(" ")[0]);
            const weekStr = this.disabledValR.split(" ")[1];
            const week = Number(weekStr.slice(1, weekStr.length - 1));
            if ((dyear > year) || (dyear == year && week < Number(wIndex * 1 + 1 * 1))) {
              return true;
            } else {
              return false;
            }
          } else if (this.disabledValL) {
            const year = Number(this.disabledValL.split(" ")[0]);
            const weekStr = this.disabledValL.split(" ")[1];
            const week = Number(weekStr.slice(1, weekStr.length - 1));
            if ((dyear < year) || (dyear == year && week > Number(wIndex * 1 + 1 * 1))) {
              return true;
            } else {
              return false;
            }
          } else {
            return false;
          }
        } catch (e) {}
      };
    }
  },
  data() {
    const curY = this.$moment().format("YYYY");// 獲取今年
    return {
      selectVal: "",
      selectShow: false,
      width: 0,
      //
      defaultYear: curY,
      stepYear: 1,
      weekList: [],
    };
  },
  mounted() {
    this.initYear(this.defaultYear);
    this.initEvent();
  },
  methods: {
    initYear(initY) {
      this.defaultYear = Number(initY);
      this.weekList = weekFormat(initY);
    },
    resetWidth() {
      const width = this.$refs.viYearSelect.offsetWidth;
      this.width = `${width}px`;
    },
    prevYear() {
      this.defaultYear -= 1 * this.stepYear;
      this.initYear(this.defaultYear);
    },
    nextYear() {
      this.defaultYear += 1 * this.stepYear;
      this.initYear(this.defaultYear);
    },
    // 年元件選擇
    selectOption(wItem, wIndex, dyear) {
      const bool = this.disabledCls(dyear, wIndex);
      if (bool) {
        // console.log("禁止選擇時間段");
        return false;
      }
      this.selectShow = false;
      let rsp = {
        startTime: `${wItem[0]} 00:00:00`,
        endTime: `${wItem[wItem.length - 1]} 23:59:59`
      };
      this.$emit("change", rsp, "week");
      this.selectVal = `${this.defaultYear} 第${wIndex * 1 + 1 * 1}周`;
    },
    showSelect() {
      if (!this.disabled) {
        this.selectShow = !this.selectShow;
        this.resetWidth();
      }
    },
    initEvent() {
      document.addEventListener("click", () => {
        this.selectShow = false;
      });
    },
  },
};
</script>

<style lang="less" scoped>
.vi-year-select {
  position:relative;
}
.search-form .vi-year-select .zTreeSelect {
  position: fixed !important;
}
  .zTreeSelect {
    background-color: #fff;
    height: 220px;
    max-width: 400px;
    overflow: auto;
    position: absolute;
    z-index: 10;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
    border-radius: 4px;
    margin-top: 5px;
    z-index: 99;
    .option {
      text-align: center;
      cursor: pointer;
      margin: 0;
      line-height: normal;
      padding: 7px 0px;
      clear: both;
      color: #515a6e;
      font-size: 14px;
      white-space: nowrap;
      list-style: none;
      cursor: pointer;
      transition: background 0.2s ease-in-out;
      width: 50%;
      display: inline-block;
    }
    .option:hover{
        background: #f3f3f3;
    }
    .option.disabledCls {
      color: #AEB8C4;
      cursor: not-allowed;
    }
  }
  .panel-top {
    height: 30px;
    border-bottom: 1px solid #DCDEE2;
    display: flex;
    justify-content: space-around;
    &:last-child, &:first-child {
        cursor: pointer;
    }
  }
  .panel-info {
    height: 190px;
    overflow: auto;
  }
  .month-info {
    font-weight: 600;
  }
  .week-list{
    padding: 2px 0px;
    &:hover{
        background: #f3f3f3;
    }
  }
</style>
自定義周選擇元件、年選擇元件
// 指定年份,返回,指定年份的周列表
function weekFormat(initY) {
  let weekList = [];
  let weekIdx = 0;
  weekList[weekIdx] = [];
  const monthDay = [31, ((initY % 4) == 0 ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // 每年的月份
  for (let i = 1; i <= monthDay.length; i++) {
    let month =  i > 9 ? i : `0${i}`;
    for (let j = 1; j <= monthDay[i - 1]; j++) {
      const day = j > 9 ? j : `0${j}`;
      const monthFirst = `${initY}-${month}-${day}`;
      let weekN = moment(`${monthFirst}`).format("dddd"); // 獲取當天星期幾
      weekList[weekIdx].push(monthFirst);
      if (weekN == "Sunday") {
        weekIdx++;
        weekList[weekIdx] = [];
      }
    }
  }
  return weekList;
}
View Code

// 年元件 yearSelect

<template>
  <div ref="viYearSelect" class="vi-year-select">
    <ui-input
            v-model="selectVal"
            :placeholder="placeholder"
            :disabled="disabled"
            readonly
      :clearable="clearable"
            @click.native.stop="showSelect"
            :suffix="selectShow ? 'ios-arrow-up' : 'ios-arrow-down'"
    />
    <div class="zTreeSelect" :style="{ width: width }" v-show="selectShow" @click.stop>
      <div>
        <div class="panel-top">
          <span @click="prevYear">
            <ui-icon type="ios-arrow-back" size="16" color="#001F45" />
          </span>
          <span>{{defaultYear}}</span>
          <span @click="nextYear">
            <ui-icon type="ios-arrow-forward" size="16" color="#001F45" />
          </span>
        </div>
        <div>
          <div
            class="option"
            :class="{'disabledCls':disabledCls(item)}"
            v-for="item in yearList"
            :key="item"
            @click="selectOption(item)"
          >
          {{item}}年</div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>

export default {
  name: "viYearSelect",
  props: {
    model: {
      type: String
    },
    clearable: {
      type: Boolean,
      default: false
    },
    placeholder: {
      type: String,
      default: "請選擇",
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    disabledValR: { // 大於當前的值,禁止選擇,值格式為: YYYY
      type: String,
      default: ""
    },
    disabledValL: { // 小於當前的值,禁止選擇,值格式為: YYYY
      type: String,
      default: ""
    },
    type: { // 下拉型別,年(year)、星期(week)、季度
      type: String,
      default: "year"
    },
    rspType: {  // 返回型別,range,"",,range例如選擇了年,那麼就返回今年的開始時間和結束時間
      type: String,
      default: "range"
    }
  },
  // model中:prop代表著我要和props的指定變數(model)相對應,event表示著事件,我觸發事件(change)的時候會改變父元件v-model的值
  model: {
    prop: "model",
    event: ""
  },
  watch: {
    model: {
      deep: true,
      immediate: true,
      handler(val) {
        this.selectVal = val;
      }
    },
    disabledValR: {
      deep: true,
      immediate: true,
      handler() {}
    },
    disabledValL: {
      deep: true,
      immediate: true,
      handler() {}
    }
  },
  computed: {
    // 年,禁止選擇項判斷
    disabledCls() {
      return function (item) {
        let bool = (this.disabledValR && item > this.disabledValR) || (this.disabledValL && item < this.disabledValL);
        return bool;
      };
    }
  },
  data() {
    return {
      selectVal: "",
      selectShow: false,
      width: 0,
      defaultYear: "",
      stepYear: 10,
      yearList: [],
    };
  },
  mounted() {
    const curY = this.$moment().format("YYYY");// 獲取今年
    this.initYear(curY);
    this.initEvent();
  },
  methods: {
    initYear(initY) {
      this.defaultYear = Math.floor(initY / this.stepYear) * this.stepYear;
      this.yearList = [];
      for (let i = this.defaultYear; i < this.defaultYear * 1 + this.stepYear; i++) {
        this.yearList.push(i);
      }
    },
    resetWidth() {
      const width = this.$refs.viYearSelect.offsetWidth;
      this.width = `${width}px`;
    },
    prevYear() {
      this.defaultYear -= this.stepYear;
      this.initYear(this.defaultYear);
    },
    nextYear() {
      this.defaultYear += this.stepYear;
      this.initYear(this.defaultYear);
    },
    // 年元件選擇
    selectOption(item) {
      const bool = this.disabledCls(item);
      if (bool) {
        // console.log("禁止選擇時間段");
        return false;
      }
      this.selectShow = false;
      if (this.rspType == "range") {
        let rsp = {
          startTime: `${item}-01-01 00:00:00`,
          endTime: `${item}-12-31 23:59:59`
        };
        this.$emit("change", rsp, "year");
      } else {
        this.$emit("change", item, "year");
      }
      this.selectVal = item;
    },
    showSelect() {
      if (!this.disabled) {
        this.selectShow = !this.selectShow;
        this.resetWidth();
      }
    },
    initEvent() {
      document.addEventListener("click", () => {
        this.selectShow = false;
      });
    },
  },
};
</script>

<style lang="less" scoped>
.vi-year-select {
  position:relative;
}
.search-form .vi-year-select .zTreeSelect {
  position: fixed !important;
}
  .zTreeSelect {
    background-color: #fff;
    height: 200px;
    max-width: 400px;
    overflow: auto;
    position: absolute;
    z-index: 10;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
    border-radius: 4px;
    margin-top: 5px;
    z-index: 99;
    .option {
        text-align: center;
        cursor: pointer;
        margin: 0;
        line-height: normal;
        padding: 7px 0px;
        clear: both;
        color: #515a6e;
        font-size: 14px;
        white-space: nowrap;
        list-style: none;
        cursor: pointer;
        transition: background 0.2s ease-in-out;
        width: 50%;
        display: inline-block;
    }
    .option:hover{
        background: #f3f3f3;
    }
    .option.disabledCls {
      color: #AEB8C4;
      cursor: not-allowed;
    }
  }
  .panel-top {
      height: 30px;
      border-bottom: 1px solid #DCDEE2;
      display: flex;
      justify-content: space-around;
      &:last-child, &:first-child {
          cursor: pointer;
      }
  }
</style>

相關文章