RMCalendar.ets 10.9 KB
import { RMCalendarBean } from './RMCalendarBean'
import { RMCalenderCell } from './RMCalendarCell'
import { ToastUtils, NetworkUtil } from 'wdKit/Index';

@Component
export struct RMCalendar {
  @State selectItem: RMCalendarBean = new RMCalendarBean()
  //选中的日期
  private selectDay: Date = new Date()
  // 开始日期
  startDate: Date = new Date()
  // 截止日期
  endDate: Date = new Date()
  // 当前时间
  private nowDate: Date  = new Date()

  //当前日期-当前显示的月份的第一天
  // private startDay: Date = new Date(
  //   this.selectDay.getFullYear(),
  //   this.selectDay.getMonth(),
  //   1
  // )
  // 是否有上一个月
  @State private hasPre: boolean = true
  // 是否有下一个月
  @State private hasNext: boolean = true
  // 标题栏高度
  titleHeight: Length = '50vp'
  // 星期标题
  weeks: string[] = ["日", "一", "二", "三", "四", "五", "六",]
  // 星期标题字体大小
  weekTitleFontSize: number | string | Resource = 12
  // 星期标题字体颜色
  weekTitleFontColor: ResourceColor = "#999999"
  // 星期标栏高度
  weekTitleHeight: Length = 30
  weekFontWeight: FontWeight = FontWeight.Bold
  // 标题字体大小
  titleFontSize: number | string | Resource = 16
  // 标题字体颜色
  titleFontColor: ResourceColor = "#333333"
  titleFontWeight: FontWeight = FontWeight.Bold
  // 日期每一项字体大小
  itemFontSize: number | string | Resource = 14
  itemFontColor: ResourceColor = "#333333"
  itemFontWeight: FontWeight = FontWeight.Bold
  // 今日字体颜色
  selectDayFontColor: ResourceColor = "#ED2800"
  // 不能使用的日期字体颜色
  disabledFontColor: ResourceColor = "#CCCCCC"
  // 选中日期字体颜色
  selectFontColor: ResourceColor = "#FFFFFF"
  // 选中日期背景颜色, 默认与selectDayFontColor一致
  selectItemBgColor: ResourceColor = "#ED2800"
  // 当前日期未选中颜色
  nowFontColor: ResourceColor = "#ED2800"
  @State private title: string = ''
  // 计算的总加载
  @State dates: Array<RMCalendarBean> = new Array()
  // 已选日期
  @State selectedDates: Array<RMCalendarBean> = new Array()
  // 自定义每一项布局
  public cellLayout?: (item: RMCalendarBean) => void
  // 仅自定义 今日 样式,当使用cellLayout时,tadayLayout无效
  selectDayLayout?: (item: RMCalendarBean) => void
  // 计算item时,如需添加更多自定义属性时使用
  reBuildDateItem?: (item: RMCalendarBean) => RMCalendarBean
  // 选择变化监听,
  onDateChange?: (date1: RMCalendarBean) => void
  onMonthChange?: (after: Date, befor: Date) => void
  // 不可选中项的点击事件
  disableCellClick?: (item: RMCalendarBean) => void

  @Builder
  createWeekTitle(item: string) {
    Text(item)
      .textAlign(TextAlign.Center)
      .fontColor(this.weekTitleFontColor)
      .fontSize(this.weekTitleFontSize)
      .fontWeight(this.weekFontWeight)
      .layoutWeight(1)
  }

  @Builder
  createCell() {
    ForEach(this.dates, (item: RMCalendarBean) => {
      RMCalenderCell({
        item: item,
        cellLayout: this.cellLayout,
        itemFontSize: this.itemFontSize,
        itemFontColor: this.itemFontColor,
        selectDay: this.selectDay.getTime(),
        itemFontWeight: this.itemFontWeight,
        selectDayFontColor: this.selectDayFontColor,
        selectDayLayout: this.selectDayLayout,
        selectItem: $selectItem,
        selectFontColor: this.selectFontColor,
        selectItemBgColor: this.selectItemBgColor,
        selectedDates: $selectedDates,
        disabledFontColor: this.disabledFontColor,
        hasPre: this.hasPre,
        hasNext: this.hasNext,
        nowFontColor: this.nowFontColor,
        disableClick: (item: RMCalendarBean) => {
          if (this.disableCellClick) {
            if (!NetworkUtil.isNetConnected()) {
              ToastUtils.showToast('网络出小差了,请检查网络后重试', 1000)
              return
            }
            this.disableCellClick(item)
          }
        },
        cellClick: (item: RMCalendarBean) => {
          if (item.isPre) {
            this.preMonth()
          } else if (item.isNext) {
            this.nextMonth()
          }
          if (this.onDateChange) {
            this.onDateChange(item)
            if (item.fullYear && item.month) {
              this.title = `${item.fullYear}年${this.getMonthStr(item.month + 1)}月`
            }
          }
        }
      })
        .width(`14.28%`)
    }, (item: RMCalendarBean) => JSON.stringify(item))
  }

  /**
   * 属性初始化
   */
  initAttr() {
    if (!this.selectItemBgColor) {
      this.selectItemBgColor = this.selectDayFontColor
    }
    this.selectDay = new Date(
      this.selectDay.getFullYear(),
      this.selectDay.getMonth(),
      this.selectDay.getDate(),
    )

    // 开始日期
    if (!this.startDate) {
      this.startDate = new Date(1970, 0, 1)
    }
    // 截止日期
    if (!this.endDate) {
      this.endDate = new Date(this.selectDay.getFullYear() + 10, 11, 31)
    }

    if (this.selectDay.getTime() < this.startDate.getTime()) {
      this.selectDay.setTime(this.startDate.getTime())
    } else if (this.selectDay.getTime() > this.endDate.getTime()) {
      this.selectDay.setTime(this.endDate.getTime())
    } else {
      this.selectDay.setTime(this.selectDay.getTime())
    }
  }

  aboutToAppear() {
    this.initAttr()
    let temp = new RMCalendarBean()
    temp.time = this.selectDay.getTime()
    this.selectItem = temp
    this.calcData()
  }

  /**
   * 下一个月
   */
  private nextMonth() {
    if (!NetworkUtil.isNetConnected()) {
      ToastUtils.showToast('网络出小差了,请检查网络后重试', 1000)
    }
    // this.dates.slice(0, this.dates.length)
    this.dates = []
    const beforDate = new Date(this.selectDay.getFullYear(), this.selectDay.getMonth())
    this.selectDay.setMonth(this.selectDay.getMonth() + 1)
    if (this.onMonthChange) {
      this.onMonthChange(new Date(this.selectDay.getFullYear(), this.selectDay.getMonth()), beforDate)
    }
    this.calcData()
  }

  /**
   * 上一个月
   */
  private preMonth() {
    if (!NetworkUtil.isNetConnected()) {
      ToastUtils.showToast('网络出小差了,请检查网络后重试', 1000)
    }
    // this.dates.slice(0, this.dates.length)
    this.dates = []
    const beforDate = new Date(this.selectDay.getFullYear(), this.selectDay.getMonth())
    this.selectDay.setMonth(this.selectDay.getMonth() - 1)
    if (this.onMonthChange) {
      this.onMonthChange(new Date(this.selectDay.getFullYear(), this.selectDay.getMonth()), beforDate)
    }
    this.calcData()
  }

  /**
   * 具体计算
   */
  private calcData() {

    this.title = `${this.selectDay.getFullYear()}年${this.getMonthStr(this.selectDay.getMonth() + 1)}月`
    this.selectDay.setDate(1)

    if (this.selectDay.getFullYear() < this.startDate.getFullYear()
      || (this.selectDay.getFullYear() == this.startDate.getFullYear() &&
        this.selectDay.getMonth() <= this.startDate.getMonth())) {
      this.hasPre = false
    } else {
      this.hasPre = true
    }

    if (this.selectDay.getFullYear() > this.endDate.getFullYear()
      || (this.selectDay.getFullYear() == this.endDate.getFullYear() &&
        this.selectDay.getMonth() >= this.endDate.getMonth())) {
      this.hasNext = false
    } else {
      this.hasNext = true
    }
    // 创建一个整月的日期,获取一个月总天数
    let selectDate: Date = new Date(
      this.selectDay.getFullYear(),
      this.selectDay.getMonth() + 1,
      0, 23, 59, 59)

    let tempDate: Date = new Date(
      this.selectDay.getFullYear(),
      this.selectDay.getMonth(),
      this.selectDay.getDate()
    )
    //获取当月的总天数
    const count = selectDate.getDate()
    //当前日期是周几
    const preCount = this.selectDay.getDay()
    const totalCount = count + preCount

    // 补齐上一个月差的天数,需要在当月展示的部分,下面计算日期循环加1天
    tempDate.setDate(this.selectDay.getDate() - preCount)

    // 当前时间除去时分秒
    this.nowDate.setHours(0,0,0,0)
    // 添加当月需要展示的日期
    for (let index = 0; index < totalCount; index++) {
      let item = new RMCalendarBean(
        tempDate.getFullYear(),
        tempDate.getMonth(),
        tempDate.getDate(),
        tempDate.getDay(),
        tempDate.getTime(),
        // @ ts-ignore
        // LunarCalendar.convertSolarToLunar(tempDate),
        (index < preCount ? true : false) || this.startDate.getTime() > tempDate.getTime(),
        (index >= preCount + count ? true : false) || this.endDate.getTime() < tempDate.getTime(),
        tempDate.getTime() == this.nowDate.getTime()
      )
      if (this.reBuildDateItem) {
        this.reBuildDateItem(item)
      }
      this.dates.push(item)
      tempDate.setDate(tempDate.getDate() + 1)
    }
  }

  build() {
    Column() {
      Image($r("app.media.iv_e_news_pager_calendar_arrow_up"))
        .width(18).height(8.5)
      Column() {
        Row() {
          Column() {
            Image(this.hasPre ? $r("app.media.iv_e_news_pager_calendar_arrow_pre")
              : $r("app.media.iv_e_news_pager_calendar_arrow_pre_gray"))
              .width(22)
              .aspectRatio(1)
          }
          .justifyContent(FlexAlign.Center)
          .height("100%")
          .aspectRatio(1)
          .onClick(() => {
            if (this.hasPre) {
              this.preMonth()
            }
          })

          Blank()
          Row() {
            Text(this.title)
              .fontSize(this.titleFontSize)
              .fontColor(this.titleFontColor)
              .fontWeight(600)
              .fontFamily('PingFang SC-Semibold')
          }

          Blank()
          Column() {
            Image(this.hasNext ? $r("app.media.iv_e_news_pager_calendar_arrow_next")
              : $r("app.media.iv_e_news_pager_calendar_arrow_next_gray"))
              .width(22)
              .aspectRatio(1)
          }
          .justifyContent(FlexAlign.Center)
          .height("100%")
          .aspectRatio(1)
          .onClick(() => {
            if (this.hasNext) {
              this.nextMonth()
            }
          })
        }
        .alignItems(VerticalAlign.Center)
        .width("100%")
        .height(this.titleHeight)

        // 星期title
        Row() {
          ForEach(this.weeks, (item: string) => {
            this.createWeekTitle(item)
          }, (item: string) => {
            return item
          })
        }
        .alignItems(VerticalAlign.Center)
        .height(this.weekTitleHeight)

        Flex({ wrap: FlexWrap.Wrap }) {
          this.createCell()
        }
        .width("100%")
      }
      .backgroundColor(Color.White)
      .margin({
        left: 35,
        right: 35
      })
      .padding(
        { bottom: 20 })
      .border({ radius: 4 })
    }
  }

  getMonthStr(month?: number): string {
    if (!month) {
      return ''
    }
    if (month <= 0) {
      return ''
    }
    if (month <= 9) {
      return '0' + month
    }
    return month + ''
  }
}