Calendar 日历组件自定义头部和内容,支持备注

先看效果图

 

 

 该日历接口入参是当前面板第一天和最后一天时间,查询区间数据。

接口返回数据格式:

        [{
            "date": "2023-05-29", // 日期
            "type": "nonWorkday", // 类型
            "description": "备注" // 备注
        }]

 

工作有点忙直接上原始代码了,有疑惑的地方可以评论留言讨论

<template>
  <div class="calendar-setting">
    <a-calendar :header-render="headerRender" @select="handleSelect" @panelChange="handlePanelChange">
      <div v-if="calendarList?.length" class="ant-fullcalendar-cell" slot="dateFullCellRender" slot-scope="value">
        <calendar-item :data="getListData(value)" />
      </div>
    </a-calendar>
    <supcon-modal
      ref="calendar_modal"
      :modal_attrs="{
        width: 475,
        height: 404,
      }"
      modal_title="日期设置"
      @modal_handle_ok="form_submit"
    >
      <div slot="content">
        <div class="modal-date">
          选择日期:<span>{{ this.selectData }}</span>
        </div>
        <supcon-form
          ref="calendar_form"
          slot="content"
          :form_attrs="{ action: 'modal' }"
          :form_default="form_default"
          :form_setting="calendar_form_person(calendarEnums)"
        />
      </div>
    </supcon-modal>
  </div>
</template>
<script>
import API from '@/api/workforce-management/duty-scheduling'
import moment from 'moment'
import { calendar_form_person } from './../../config/duty-setting.js'
export default {
  components: {
    supconForm: () => import('@/components/supcon-form/supcon-form'),
    supconModal: () => import('@/components/supcon-modal/supcon-modal'),
    calendarItem: () => import('./calendar-item.vue'),
  },
  data() {
    return {
      calendar_form_person,
      form_default: {},
      selectData: '',
      calendarEnums: [],
      calendarList: [],
      firstDate: '',
      lastDate: '',
    }
  },
  computed: {},
  created() {
    
  },
  methods: {
    handlePanelChange(value) {
      const { firstDate, lastDate } = this.getFirstDateAndLastDateOnThePanel(value)
      this.firstDate = firstDate
      this.lastDate = lastDate
      this.queryList()
    },
    getListData(value) {
      let date = moment(value).format('yyyy-MM-DD')
      if (this.calendarList?.length) {
        let data = moment(value).format('DD')
        let day = moment(value).day()
        let target = this.calendarList?.find((item) => item?.date === date)
        return {
          type: target?.type,
          desc: target?.description,
          bg: target?.type,
          data,
          isRed: day === 0 || day === 6,
        }
      } else {
        return {}
      }
    },
    queryList() {
      
    },
    // 单个日期点击
    handleSelect(value) {
      this.selectData = moment(value).format('yyyy-MM-DD')
      let target = this.calendarList.find((item) => item?.date === this.selectData)
      if (target.id) {
        this.form_default = target
      }
      this.$refs.calendar_modal.modal_visible = true
    },
    async form_submit() {
      this.$refs.calendar_form.supcon_form.validateFields((err, fields_value) => {
        if (err !== null) {
          return false
        }
        console.log(fields_value)
      })
    },
    // 自定义头部
    headerRender({ value, type, onChange, onTypeChange }) {
      this.handlePanelChange(value)
      const start = 0
      const end = 12
      const monthOptions = []
      const current = value.clone()
      const localeData = value.localeData()
      const months = []
      for (let i = 0; i < 12; i++) {
        current.month(i)
        months.push(localeData.monthsShort(current))
      }
      for (let index = start; index < end; index++) {
        monthOptions.push(
          <a-select-option class="month-item" key={`${index}`}>
            {months[index]}
          </a-select-option>
        )
      }
      const month = value.month()
      const year = value.year()
      const options = []
      for (let i = year - 10; i < year + 10; i += 1) {
        options.push(
          <a-select-option key={i} value={i} class="year-item">
            {i}
          </a-select-option>
        )
      }
      return (
        <div style={{ padding: '10px' }}>
          <a-row type="flex" justify="space-between">
            <a-col></a-col>
            <a-col></a-col>
            <a-col>
              <a-select
                size="large"
                dropdownMatchSelectWidth={false}
                class="my-year-select"
                onChange={(newYear) => {
                  const now = value.clone().year(newYear)
                  onChange(now)
                }}
                value={String(year)}
              >
                {options}
              </a-select>
              <a-select
                style="margin: 0 12px"
                size="large"
                dropdownMatchSelectWidth={false}
                value={String(month)}
                onChange={(selectedMonth) => {
                  const newValue = value.clone()
                  newValue.month(parseInt(selectedMonth, 10))
                  onChange(newValue)
                }}
              >
                {monthOptions}
              </a-select>
              <a-date-picker
                size="large"
                defaultValue={value}
                onChange={(selectedMonth) => {
                  onChange(selectedMonth)
                }}
              />
            </a-col>
          </a-row>
        </div>
      )
    },
    // 获取面板第一个日期和最后一个日期
    getFirstDateAndLastDateOnThePanel(date) {
      const firstDate = moment(date).startOf('month')
      const lastDate = moment(date).endOf('month')
      const firstDateDay = firstDate.day()
      firstDate.subtract(firstDateDay, 'days')
      lastDate.add(43 - Number(lastDate.format('DD')) - firstDateDay, 'days')
      return {
        firstDate: firstDate.format('YYYY-MM-DD'),
        lastDate: lastDate.format('YYYY-MM-DD'),
      }
    },
  },
}
</script>
<style lang="less" scoped>
.calendar-setting {
  width: 100%;
  height: 100%;
  padding: 12px 24px;
  /deep/ .ant-fullcalendar-column-header {
    background: #e6f7ff;
    position: relative;
    top: 3px;
  }
}
.events {
  list-style: none;
  margin: 0;
  padding: 0;
}
.events .ant-badge-status {
  overflow: hidden;
  white-space: nowrap;
  width: 100%;
  text-overflow: ellipsis;
  font-size: 12px;
}
.notes-month {
  text-align: center;
  font-size: 28px;
}
.notes-month section {
  font-size: 28px;
}
.modal-date {
  margin-bottom: 16px;
  font-family: 'PingFang SC';
  font-style: normal;
  font-weight: 400;
  font-size: 14px;
  color: #000000;
  opacity: 0.85;
  span {
    opacity: 0.65;
  }
}
.fontColor {
  color: #f00;
}
.nonWorkday {
  background: #fff1f0;
}
.workday {
  background: rgba(0, 0, 0, 0.04);
}
.full-header-no {
  padding: 2px 6px;
  background: #ff4d4f;
  font-family: 'PingFang SC';
  font-style: normal;
  font-weight: 400;
  font-size: 14px;
  line-height: 22px;
  color: #ffffff;
}
.full-header {
  padding: 2px 6px;
  background: rgba(0, 0, 0, 0.45);
  font-family: 'PingFang SC';
  font-style: normal;
  font-weight: 400;
  font-size: 14px;
  line-height: 22px;
  color: #ffffff;
}
.ant-fullcalendar-value {
  width: 100%;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}
.ant-fullcalendar-content {
  margin-top: 12px;
}
</style>

 calendar-item子组件

<template>
  <div :class="['ant-fullcalendar-date', data?.bg]">
    <div :class="['ant-fullcalendar-value', data?.isRed && 'fontColor']">
      <template v-if="data?.type">
        <div v-if="data?.type === 'nonWorkday'" class="full-header-no">休</div>
        <div v-if="data?.type === 'workday'" class="full-header">班</div>
      </template>
      <div v-else></div>
      {{ data?.data }}
    </div>
    <div class="ant-fullcalendar-content" v-if="data?.desc">备注:{{ data?.desc }}</div>
  </div>
</template>
<script>
export default {
  props: {
    data: {
      type: Object,
      default: () => {},
    },
  },
  components: {},
  data() {
    return {}
  },
  computed: {},
  created() {},
  methods: {},
}
</script>
<style lang="less" scoped>
.fontColor {
  color: #f00;
}
.nonWorkday {
  background: #fff1f0;
}
.workday {
  background: rgba(0, 0, 0, 0.04);
}
.full-header-no {
  padding: 2px 6px;
  background: #ff4d4f;
  font-family: 'PingFang SC';
  font-style: normal;
  font-weight: 400;
  font-size: 14px;
  line-height: 22px;
  color: #ffffff;
}
.full-header {
  padding: 2px 6px;
  background: rgba(0, 0, 0, 0.45);
  font-family: 'PingFang SC';
  font-style: normal;
  font-weight: 400;
  font-size: 14px;
  line-height: 22px;
  color: #ffffff;
}
.ant-fullcalendar-value {
  width: 100%;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}
.ant-fullcalendar-content {
  margin-top: 12px;
}
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值