日期计划

2019-09-30  本文已影响0人  __笑我一世沉沦丶
gifhome_906x648_8s.gif

我们先来个看图说话,这个二月份有28天,1号是星期五。那是不是说,我们只要从周五开始,按顺序渲染出28个'main__block'就好了呢?其实就是这样,关键是怎么把我们的1号定位到周五,只要这个能够准确定位到,我们的日历自然就出来了。

// 定义每个月的天数,如果是闰年第二月改为29天
// year=2019;month=1(js--month=0~11)
let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
    daysInMonth[1] = 29;
}
// 获得指定年月的1号是星期几
let targetDay = new Date(year, month, 1).getDay();
// 将要在calendar__main中渲染的列表
let total_calendar_list = [];
let preNum = targetDay;
// 首先先说一下,我们的日期是(日--六)这个顺序也就是(0--6)
// 有了上述的前提我们可以认为targetDay为多少,我们就只需要在total_calendar_list的数组中push几个content为''的obj作为占位
if (targetDay > 0) {
    for (let i = 0; i < preNum; i++) {
        let obj = {
            type: "pre",
            content: ""
        };
        total_calendar_list.push(obj);
    }
}

这样一来,1号的位置自然而然就到了我们需要的星期五了,接下来就只需要按顺序渲染就ok啦。下面是剩下日期数组填充,填充完毕之后return出来供我们view层使用。
for (let i = 0; i < daysInMonth[month]; i++) {
let obj = {
type: "normal",
content: i + 1
};
total_calendar_list.push(obj);
}
nextNum = 6 - new Date(year, month+1, 0).getDay()
// 与上面的type=pre同理
for (let i = 0; i < nextNum; i++) {
let obj = {
type: "next",
content: ""
};
total_calendar_list.push(obj);
}
return total_calendar_list;

data() {
    return {
        // ...
        selectedYear: new Date().getFullYear(),
        selectedMonth: new Date().getMonth(),
        selectedDate: new Date().getDate()
    };
}

handlePreMonth() {
    if (this.selectedMonth === 0) {
        this.selectedYear = this.selectedYear - 1
        this.selectedMonth = 11
        this.selectedDate = 1
    } else {
        this.selectedMonth = this.selectedMonth - 1
        this.selectedDate = 1
    }
}

handleNextMonth() {
    if (this.selectedMonth === 11) {
        this.selectedYear = this.selectedYear + 1
        this.selectedMonth = 0
        this.selectedDate = 1
    } else {
        this.selectedMonth = this.selectedMonth + 1
        this.selectedDate = 1
    }
}

就是这么简单,需要注意的点是跨年的时间转换,我们需要在变更月份的同时把年份也改变,这样才能渲染出正确的日期。
也许大家会有疑问,怎么变更了月份或年份之后不需要重新计算一次日期呢?其实是有计算的,不知大家是否还记得,vue可是数据驱动变更的,我们只需要关注数据的变更即可,其他东西vue都会帮我们解决。

handleDayClick(item) {
    if (item.type === 'normal') {
        // do anything...
        this.selectedDate = Number(item.content)
    }
}

在渲染列表的时候我就给每一个block绑定了click事件,这样做的好处就是调用十分方便,点击每一个block的时候,可以获取该block的内容然后do anything you like
当然我们也可以给外层的父级元素绑定事件监听,通过事件流来解决每个block的点击事件,这里看个人习惯~毕竟元素数量不是特别多
日历完成之后再进行相关的数据操作,以下是实现gif图的完整页面代码

<template>
  <div class="mywk__calendar">
    <div class="calendar">
      <div class="calendar__header">
        <div class="header__pre" @click="handlePreMonth">

        </div>
        <div class="header__title">
          {{selectedYear}}年{{selectedMonth + 1}}月{{selectedDate}}日
        </div>
        <div class="header__next" @click="handleNextMonth">

        </div>
        <div class="rightStyle">
          <div class="boxStyle">
            <div class="fontStyle" style="background:#1976d2;"></div>新建计划
          </div>
          <div class="boxStyle">
            <div class="fontStyle" style="background:#4caf50;"></div>计划进行中
          </div>
          <div class="boxStyle">
            <div class="fontStyle" style="background:#3f51b5"></div>计划已完成
          </div>
        </div>
      </div>

      <div class="calendar__main">
        <div class="main__block-head" v-for="(item, index) in calendarHeader" :key="index">
          {{item}}
        </div>

        <div :class="`main__block ${(item.type === 'pre' || item.type === 'next') ? 'main__block-not' : ''} ${item.type2 === 'pre' ? 'extraStyle' : ''} ${(item.content === selectedDate && item.type === 'normal') && 'main__block-today'}`"
             @click="handleDayClick(item)" v-for="(item, index) in total_calendar_list" :key="item.type + item.content + `${index}`">
          <p class="dateNum">{{item.content}}</p>
          <div class="content" v-for="(list, index) in item.arr" :key="index">
            <el-tooltip class="item" effect="dark" :content="list.storeCode+'-'+list.storeName" placement="left-start">
              <el-button class="btnClass" :style="changeColor(list)">{{list.storeCode}}-{{list.storeName}}</el-button>
            </el-tooltip>
            <div class="cancelDiv" v-if="list.state === 1"></div>
            <i @click="cancelStore(list)" v-if="list.state === 1" class="el-icon-circle-close cancelIcon"></i>
          </div>
          <img  @click="chooseStore(item)" class="iconClass" :style="`${item.content === selectedDate && item.type === 'normal' && item.type2 !== 'pre' ? 'top:4px' : 'display:none'}`" src="@/../static/add22.png" alt="">
        </div>
      </div>
    </div>

    <el-dialog
      title="选择店铺"
      :visible.sync="dialogVisible"
      width="380px">
      <el-autocomplete
        v-loading="loading"
        class="inline-input"
        v-model="searchInfo.storeName"
        :fetch-suggestions="querySearch"
        placeholder="请选择店铺列表"
        size="mini"
        clearable
        ref="input"
        :autofocus="focus"
        style="width:330px"
        @select="handleSelect"
      >
        <template slot-scope="props">
          <div class="name">{{props.item.storeCode}}-{{ props.item.storeName }}</div>
        </template>
      </el-autocomplete>
      <span slot="footer" class="dialog-footer">
        <el-button @click="cancel" size="mini">取 消</el-button>
        <el-button type="primary" @click="confirm" size="mini">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import Device2 from '@/api/device2'
export default {
  data () {
    return {
      calendarHeader: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
      selectedYear: new Date().getFullYear(),
      selectedMonth: new Date().getMonth(),
      selectedDate: new Date().getDate(),
      dialogVisible: false,
      reqStore: [],
      searchInfo: {
        storeName: '',
        storeId: '',
        storeCode: '',
        planDate: ''
      },
      focus: false,
      event: [],
      total_calendar_list: [],
      loading: false,
      planList: []
    }
  },
  mounted () {
    this.displayDaysPerMonthT(this.selectedYear)
  },
  methods: {
    changeColor (list) {
      switch (list.state) {
        case 1:
          return 'background:#1976d2;'
        case 2:
          return 'background:#4caf50;'
        case 3:
          return 'background:#3f51b5'
        default:
          return 'background:#fff'
      }
    },
    cancelStore (info) {
      if (info.state !== 1) {
        this.$message.warning('任务只有在新建状态才能删除')
        return
      }
      this.$confirm('此操作将永久删除该计划, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        var url = '/abnormal/plan/delete/' + info.planItemId
        Device2.req2(url, 'post').then(res => {
          this.$message.success('删除成功')
          this.displayDaysPerMonthT(this.selectedYear)
          this.reqStore.push(info)
        })
      })
    },
    confirm () {
      var url = '/abnormal/plan/save'
      var json = this.searchInfo
      if (!this.searchInfo.storeName) {
        this.$message.warning('请选择店铺再进行保存操作')
        return
      }
      Device2.req2(url, 'post', json).then(res => {
        if (res.data.code === 0) {
          this.$message.success('新增计划成功')
          this.dialogVisible = false
          this.displayDaysPerMonthT(this.selectedYear)
          this.reqStore.forEach((item, index) => {
            if (item.storeId === json.storeId) {
              this.reqStore.splice(index, 1)
            }
            this.clearSearchInfo()
          })
        }
      })
    },
    chooseStore (info) {
      this.dialogVisible = true
      this.searchInfo.planDate = info.date + ' 00:00:00'
      var that = this
      var url = '/abnormal/plan/storeSelect'
      this.loading = true
      Device2.req(url, 'get').then(res => {
        this.loading = false
        if (res.data.code === 0) {
          var arr = res.data.stores
          this.reqStore = arr
          setTimeout(function () {
            that.$nextTick(() => {
              that.$refs.input.$el.querySelector('input').focus()
            })
          }, 300)
        }
      })
    },
    cancel () {
      this.dialogVisible = false
      this.focus = false
      this.clearSearchInfo()
    },
    clearSearchInfo () {
      this.searchInfo.storeName = ''
      this.searchInfo.storeCode = ''
      this.searchInfo.storeId = ''
      this.searchInfo.planDate = ''
    },
    displayDaysPerMonthT (year) {
      var month2 = this.selectedMonth + 1
      if (month2 < 10) {
        month2 = '0' + month2
      }
      var url = '/abnormal/plan/' + this.selectedYear + month2
      this.loading = true
      Device2.req(url, 'get').then(res => {
        this.loading = true
        if (res.data.code === 0) {
          this.loading = false
          var arr = res.data.planList
          this.planList = arr
          // 定义每个月的天数,如果是闰年第二月改为29天
          let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

          if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0) {
            daysInMonth[1] = 29
          }
          // 定义上个月的天数
          let daysPreMonth = [].concat(daysInMonth)
          daysPreMonth.unshift(daysPreMonth.pop())
          // 定义这个月月初需要添加的天数
          let addDaysFromPreMonth = new Array(12).fill(null).map((item, index) => {
            let day = new Date(year, index, 1).getDay()
            if (day === 0) {
              return 6
            } else {
              return day - 1
            }
          })
          // 定义的日历列表数组
          var arr2 = new Array(12).fill([])
          let total_calendar_list = arr2.map((month, monthIndex) => {
            let addDays = addDaysFromPreMonth[monthIndex] + 1,
              daysCount = daysInMonth[monthIndex],
              daysCountPre = daysPreMonth[monthIndex],
              monthDate = []
            if (addDays >= 7) {
              addDays = addDays - 7
            }
            for (; addDays > 0; addDays--) {
              var days = daysCountPre--
              let obj = {
                content: days,
                type: 'pre',
                arr: []
              }
              monthDate.unshift(obj)
            }
            for (let i = 1; i <= daysCount; ++i) {
              let day = i
              if (i < 10) {
                day = '0' + i
              }
              let obj = {
                content: i,
                type: 'normal',
                date: this.selectedYear + '-' + month2 + '-' + day,
                arr: []
              }
              if (this.compareDate(i)) {
                obj.type2 = 'pre'
              }
              arr.forEach(item => {
                let planDate = new Date(item.planDate)
                var year = planDate.getFullYear()
                var month = planDate.getMonth()
                var dayTime = planDate.getDate()
                this.reqStore.forEach((item2, index) => {
                  if (item2.storeId === item.storeId) {
                    this.reqStore.splice(index, 1)
                  }
                })
                if (this.selectedYear === year && this.selectedMonth === month) {
                  if (i === dayTime) {
                    obj.arr.push({
                      storeName: item.storeName,
                      storeCode: item.storeCode,
                      storeId: item.storeId,
                      planDate: item.planDate,
                      state: item.state,
                      planItemId: item.planItemId
                    })
                  }
                }
              })
              monthDate.push(obj)
            }
            if (monthDate.length > 35) {
              for (let i = 42 - monthDate.length, j = 0; j < i; ) {
                let obj = {
                  content: ++j,
                  type: 'next',
                  arr: []
                }
                arr.forEach(item => {
                  let planDate = new Date(item.planDate)
                  var year = planDate.getFullYear()
                  var month = planDate.getMonth()
                  var dayTime = planDate.getDate()
                  if (this.selectedYear === year && this.selectedMonth === month) {
                    if (i === dayTime) {
                      obj.arr.push({
                        storeName: item.storeName,
                        storeCode: item.storeCode,
                        storeId: item.storeId,
                        planDate: item.planDate,
                        state: item.state,
                        planItemId: item.planItemId
                      })
                    }
                  }
                })
                monthDate.push(obj)
              }
            } else {
              for (let i = 35 - monthDate.length, j = 0; j < i;) {
                let obj = {
                  content: ++j,
                  type: 'next',
                  arr: []
                }
                arr.forEach(item => {
                  let planDate = new Date(item.planDate)
                  var year = planDate.getFullYear()
                  var month = planDate.getMonth()
                  var dayTime = planDate.getDate()
                  if (this.selectedYear === year && this.selectedMonth === month) {
                    if (i === dayTime) {
                      obj.arr.push({
                        storeName: item.storeName,
                        storeCode: item.storeCode,
                        storeId: item.storeId,
                        planDate: item.planDate,
                        state: item.state,
                        planItemId: item.planItemId
                      })
                    }
                  }
                })
                monthDate.push(obj)
              }
            }
            return monthDate
          })
          this.total_calendar_list = total_calendar_list[this.selectedMonth]
        }
      }).catch(err => {
        this.loading = false
      })
    },
    handleDayClick (item) {
      if (item.type === 'normal' && !item.type2) {
        // do anything...
        this.selectedDate = Number(item.content)
      }
    },
    handlePreMonth () {
      if (this.selectedMonth === 0) {
        this.selectedYear = this.selectedYear - 1
        this.selectedMonth = 11
      } else {
        this.selectedMonth = this.selectedMonth - 1
      }
      this.isSelectDate()
      this.displayDaysPerMonthT(this.selectedYear)
    },
    handleNextMonth () {
      if (this.selectedMonth === 11) {
        this.selectedYear = this.selectedYear + 1
        this.selectedMonth = 0
      } else {
        this.selectedMonth = this.selectedMonth + 1
      }
      this.isSelectDate()
      this.displayDaysPerMonthT(this.selectedYear)
    },
    compareDate (count) {
      var date = new Date()
      var year = date.getFullYear()
      var month = date.getMonth()
      var day = date.getDate()
      var result
      if (this.selectedYear <= year && this.selectedMonth < month) {
        result = true
      } else if (this.selectedMonth === month && count < day) {
        result = true
      } else {
        result = false
      }
      return result
    },
    isSelectDate () {
      var date = new Date()
      var year = date.getFullYear()
      var month = date.getMonth()
      var day = date.getDate()
      if (this.selectedYear === year && this.selectedMonth === month) {
        this.selectedDate = day
      } else {
        this.selectedDate = 1
      }
    },
    querySearch (queryString, cb) {
      var reqStore = this.reqStore
      var results = queryString ? reqStore.filter(this.createFilter(queryString)) : reqStore
      // // 调用 callback 返回建议列表的数据
      cb(results)
    },
    handleSelect (item) {
      this.searchInfo.storeName = item.storeCode + '-' + item.storeName
      this.searchInfo.storeId = item.storeId
      this.searchInfo.storeCode = item.storeCode
    },
    createFilter (queryString) {
      return (item) => {
        return ((item.storeCode + '-' + item.storeName).toLowerCase().indexOf(queryString.toLowerCase()) !== -1)
      }
    }
  }
}
</script>

<style lang="scss">
  @function pxWithVw($n) {
    @return 100vw * $n / 375;
  }

  @function pxWithVwMax($n) {
    @return 480px * $n / 375;
  }
  .rightStyle{
    position:absolute;right:10px;top:10px;
    display: flex;
  }
  .boxStyle{
    display: flex;align-items: center;font-size:12px;
  }
  .fontStyle{
    width:18px;height:10px;margin:0 10px;border-radius:5px;
  }
  p{
    padding: 0;
  }
  .content{
    position: relative;
  }
  .cancelDiv{
    position: absolute;
    right:6px;
    top:16px;
    width: 10px;
    height:10px;
    border-radius:50%;
    background: #ffffff;
    z-index:1
  }
  .cancelIcon{
    color:red;
    position: absolute;
    right:3px;
    top:14px;
    font-size:16px;
    cursor: pointer;
    z-index:2
  }
  .btnClass{
    width:100% !important;
    padding: 7px 5px !important;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
    font-size: 11px !important;
    margin-top:10px !important;
    color:#fff !important;
  }
  .dateNum{
    position: absolute;
    top:5px;right:5px;
  }
  .iconClass{
    position: absolute;top:0px;left:8px;
    font-size:16px;
    color:#eee;cursor: pointer;
    width:18px;
    transition: top 1s ease-in-out;
  }
  .mywk__calendar {
    width: 92%;
    margin: 0 auto;
    display: flex;
    justify-content: space-around;
    flex-wrap: wrap;
  }

  .tips {
    margin: 15px 0 0 0;
    text-align: center;
  }

  .calendar {
    position: relative;
    flex-shrink: 0;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    margin: 20px 0 0 0;
    border-radius: 4px;
    background-color: white;
    box-shadow: 0 0 10px rgba(208, 208, 208, 0.5);
    padding-bottom: 40px;
    padding-top: 20px;

    .calendar__header {
      color: #2c3135;
      font-size: 16px;
      width: pxWithVw(315);
      max-width: pxWithVwMax(315);
      display: flex;
      align-items: center;
      justify-content: space-between;
      line-height: 22px;
      margin-top: 17px;

      .header__title {
        font-size: 16px;
        letter-spacing: 1px;
      }
      .header__pre:hover{
        border: 1px solid #ddd;
        box-shadow: 0 0 3px #aaa;
      }
      .header__pre {
        height: 24px;
        width: 24px;
        position: relative;
        border-radius: 50%;
        cursor: pointer;
        &:after {
          content: " ";
          display: inline-block;
          height: 9px;
          width: 9px;
          border-width: 2px 2px 0 0;
          border-color: #c8c8cd;
          border-style: solid;
          transform: matrix(0.71, 0.71, -0.71, 0.71, 0, 0) rotate(180deg);
          position: absolute;
          top: 50%;
          margin-top: -4px;
          right: 4px;
        }
      }
      .header__next:hover{
        border: 1px solid #ddd;
        box-shadow: 0 0 3px #aaa;
      }
      .header__next {
        height: 24px;
        width: 24px;
        position: relative;
        border-radius: 50%;
        cursor: pointer;
        &:after {
          content: " ";
          display: inline-block;
          height: 9px;
          width: 9px;
          border-width: 2px 2px 0 0;
          border-color: #c8c8cd;
          border-style: solid;
          transform: matrix(0.71, 0.71, -0.71, 0.71, 0, 0);
          position: absolute;
          top: 50%;
          margin-top: -4px;
          right: 7px;
        }
      }
    }

    .calendar__main {
      width: 90%;
      display: flex;
      justify-content: space-around;
      flex-wrap: wrap;
      padding-top: 19px;

      .main__block {
        width: 14%;
        min-height: 70px;
        padding: 20px 5px 15px 5px;
        margin-bottom: 15px;
        border-radius: 2px;
        font-size: 12px;
        border: 1px solid #efefef;
        align-items: center;
        justify-content: center;
        color: #666666;
        background-color: #fff;

        flex-shrink: 0;
        position: relative;

        .main__block-piont {
          width: 5px;
          height: 5px;
          border-radius: 50%;
          background-color: #cce4ff;
          position: absolute;
          left: calc(50% - 2.5px);
          bottom: 0;
        }
      }
      .extraStyle{
        background-color: #efefef;
      }
      .main__block-not {
        background-color: #edf2f5;
        color: #7f8fa4;
      }
      .main__block-today {
        transition: 0.5s all;
        background-color: #cce4ff;
        box-shadow: 0 2px 6px rgba(171, 171, 171, 0.5);
      }
      .main__block-head {
        width: 14.2%;
        margin-bottom: 15px;
        border-radius: 2px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 12px;
        color: #7f8fa4;
        background-color: #fff;
        flex-shrink: 0;
      }
    }
  }
</style>



上一篇下一篇

猜你喜欢

热点阅读