当前位置: 首页 > article >正文

vue3+vite+tdesign实现日历式可编辑的排课班表

近期,在项目开发中,我们面临实现一个日历式、可编辑排班填写功能的需求。初步方案采用tdesign的Calendar组件,尽管其支持编辑功能,但在提取每日排班信息时操作繁琐,因此该方案被弃用。随后,我们决定自主研发该功能,尽管看似直观,开发过程中仍面临诸多挑战。本文旨在总结此次开发经历,希望对有类似需求的开发者有所帮助。

本篇文章开发环境的安装就不进行详细阐述,着重阐述如何使用vue3+tdesign实现日历式可编辑的排班填写功能。

目录

 一、安装tdesign

二、实现年份、月份下拉框

1.安装dayjs

2.年份下拉框样式

3.获取所有年份

4.获取月份

三、周期显示

四、可编辑日历

1.获取下拉框值班人员数据

2.获取每天值班人

3.处理选择每个年份、月份所对应的周期及天数

五、全部代码、效果展示


 一、安装tdesign

使用npm安装

npm i tdesign-vue-next

二、实现年份、月份下拉框

对于年份和月份下拉框选择,这里未使用tdesign自带的日期选择组件,但使用了他的select下拉框组件,另外这里还使用到了dayjs,用于获取不同年份。

1.安装dayjs

npm install dayjs

2.年份下拉框样式

 这个实现起来比较简单一些,其实就是使用tdesign的select选择器这个组件就行。

<template>
  <div class="calender-top">
    <t-select
      v-model="year"
      :options="optionsYear"
      clearable
      size="medium"
      @change="handleYearChange"
      style="width: 5vw; margin-right: 1vw"
    />
  </div>
</template>

<script setup>
import { ref, getCurrentInstance, onMounted, computed } from 'vue'
//当前年份
const year = ref('')
//所有年份
const optionsYear = ref([])
//选择年份
const handleYearChange = val => {}
</script>

<style lang="less" scoped>
.calender-top {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 1vw 0;
  :deep .t-popup__content {
    width: 5vw !important;
  }
  :deep .t-input__inner {
    text-align: center;
    font-size: 0.8vw;
  }
}
</style>

3.获取所有年份

以上代码中只是实现了下拉框的具体样式,其实下拉框的内容还是空的,下面就是如何使用dayjs实现获取所有的年份。因为要求在刚进行页面时需显示当前年份,所以在v-model绑定的year这里,就需要使用dayjs来获取目前所处的年份,具体如下:

//这个代码十分重要,没有这个dayjs无法使用
const context = getCurrentInstance()?.appContext.config.globalProperties
const dayjs = context?.$dayjs
//当前年份
const year = ref(dayjs().format('YYYY年'))

获取所有年份这里具体写了一个方法,大概得步骤就是,首先先写一个生成年份数组的方法,然后确定当前的年份,规定一下过去的年份和未来年份数量,使用刚刚的方法进行加减即可,具体代码如下:

// 生成年份数组的函数
const generateYears = (startYear, endYear) => {
  const years = []
  for (let i = startYear; i <= endYear; i++) {
    years.push({
      label: `${i}年`,
      value: i
    })
  }
  return years
}
//获取当前年份-月份的数据
const getYearData = () => {
  //当前年份
  const currentYear = dayjs().year()
  // 过去的年份数量
  const pastYears = 30
  // 未来的年份数量
  const futureYears = 50
  optionsYear.value = generateYears(currentYear - pastYears, currentYear + futureYears)
  // console.log(optionsYear.value, '年份')
}
onMounted(() => {
  getYearData()
})

4.获取月份

获取月份这里我未使用以上方式进行开发,因为月份数据涉及的少,所以在前端这里我写了一个JSON数据,直接进行复用即可,另外样式和年份的差不多,具体如下:

<template>
  <div class="calender-top">
    <t-select
      v-model="year"
      :options="optionsYear"
      clearable
      size="medium"
      @change="handleYearChange"
      style="width: 5vw; margin-right: 1vw"
    />
    <t-select
      v-model="month"
      :options="optionsMonth"
      clearable
      size="medium"
      @change="handleMonthChange"
      style="width: 5vw; margin-right: 1vw"
    />
  </div>
</template>

<script setup>
import { ref, getCurrentInstance, onMounted, computed } from 'vue'
import { monthList } from '@/utils/year-month.js'
//当前月份
const month = ref(dayjs().format('MM月'))
//所有月份
const optionsMonth = ref([])
//选择月份
const handleMonthChange = val => {}
//获取当前年份-月份的数据
const getYearData = () => {
  optionsMonth.value = monthList
}
onMounted(() => {
  getYearData()
})
</script>

monthList的具体数据显示如下:

//规定月份列表
export const monthList = [
  {
    label: '1月',
    value:'01'
  },
  {
    label: '2月',
    value:'02'
  },
  {
    label: '3月',
    value:'03'
  },
  {
    label: '4月',
    value:'04'
  },
  {
    label: '5月',
    value:'05'
  },
  {
    label: '6月',
    value:'06'
  },
  {
    label: '7月',
    value:'07'
  },
  {
    label: '8月',
    value:'08'
  },
  {
    label: '9月',
    value:'09'
  },
  {
    label: '10月',
    value:'10'
  },
  {
    label: '11月',
    value:'11'
  },
  {
    label: '12月',
    value:'12'
  }
]

三、周期显示

上述阐述了年份和月份下拉框的实现,做日历的话还缺少周期数,接下来是实现具体的周期,这个样式的话相对来说比较简单,涉及到flex布局、ul和li列表,另外周期数据其实也是固定的,和月份一样也是做了一个JSON数据。

//规定周期列表
export const weekList = [
  {
    label: '一',
    value:'1'
  },
  {
    label: '二',
    value:'2'
  },
  {
    label: '三',
    value:'3'
  },
  {
    label: '四',
    value:'4'
  },
  {
    label: '五',
    value:'5'
  },
  {
    label: '六',
    value:'6'
  },
  {
    label: '日',
    value:'7'
  }
]

以下是具体样式

<template>
  <ul class="canlder-weekList">
    <li class="item-top" v-for="(item, index) in optionWeek" :key="index">
      <h1>{{ item.label }}</h1>
    </li>
  </ul>
</template>

<script setup>
import { ref, getCurrentInstance, onMounted, computed } from 'vue'
import { weekList } from '@/utils/year-month.js'
//所有星期
const optionWeek = ref([])
//获取当前周期的数据
const getYearData = () => {
  optionWeek.value = weekList
}
onMounted(() => {
  getYearData()
})
</script>

<style lang="less" scoped>
.canlder-weekList {
  display: flex;
  align-items: center;
  // justify-content: space-between;
  // padding: 0 1vw;
  padding: 0.5vw 0 0 1vw;
  .item-top {
    // display: flex;
    width: 6vw;
    margin: 1vw 0.6vw 0 0;

    h1 {
      text-align: center;
      font-size: 1.2vw;
      font-weight: 500;
      color: #333;
    }
  }
}
</style>

四、可编辑日历

接下来就是本篇中重要内容了,首先先来实现日历的具体样式,他的需求功能是,每天中对应一个下拉框,下来框是可选择排班的人员,然后下方就是对应的日期天数。下方是具体代码:

<template>
  <div class="canlder-dayList">
    <div class="item-list" v-for="(item, index) in dayList" :key="index">
      <!-- <div class="name name-color">{{ item.name }}</div> -->
      <t-select
        v-model="item.name"
        clearable
        size="medium"
        @change="handleStuffChange($event, index)"
        :options="optionsName"
        class="name name-color"
      />
      <!-- <div class="number number-color">{{ item.date.slice(8, 10) }}</div> -->
      <div class="number number-color">{{ dayjs(item.date).format('DD') }}</div>
    </div>
  </div>
</template>

<script setup>
import { ref, getCurrentInstance, onMounted, computed } from 'vue'
const dayList = ref([])
//所有人员
const optionsName = ref([])
//当前选择人员
const handleStuffChange = (value, index) => {}
onMounted(() => {})
</script>

<style lang="less" scoped>
.canlder-dayList {
  // width: 15%;
  display: flex;
  // flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  padding: 0.5vw 0 0 0.8vw;
  .item-list {
    width: 6vw;
    margin: 1vw 0.6vw 0 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    .name,
    .number {
      width: 5vw;
      height: 2.5vw;
      font-size: 0.8vw;
      line-height: 2.5vw;
      text-align: center;
    }
    .name-color {
      color: #333;
      background-color: #d8d8d8;
      // background-color: rgb(216, 250, 200);
    }
    .number-color {
      color: #fff;
      background-color: rgb(116, 159, 178);
      // background-color: rgb(138, 189, 114);
    }
    :deep .t-input {
      // background-color: rgb(216, 250, 200);
      background-color: #d8d8d8;
    }
    :deep .t-input__inner {
      font-size: 0.8vw;
      text-align: center;
    }
  }
}
</style>

1.获取下拉框值班人员数据

上述代码写完我们会发现,页面上其实啥也没有,具体原因是源于还没做数据的获取,接下来就是如何获取下来框值班人,因为我这里的axios是进行了封装之后的,所以这里我展示获取数据的方式仅用了具体的方法。

<script setup>
import { ref, getCurrentInstance, onMounted, computed } from 'vue'
import { getAllDutyPerson, getMonthDutyPerson, modifyDutyPerson } from '@/api/schedule-write.js'
const dayList = ref([])
//所有人员
const optionsName = ref([])
//当前选择人员
const handleStuffChange = (event, itemIndex) => {
  const selectedValue = event
  // console.log(selectedValue, '选择人员')
  const selectedOption = optionsName.value.find(option => option.value === selectedValue)
  // console.log(selectedOption, '所选人员')
  dayList.value[itemIndex].name = selectedOption.label
  dayList.value[itemIndex].id = selectedOption.id
}
//获取所有值班人员--下拉框
const getAllDutyPersonData = params => {
  return new Promise((resolve, reject) => {
    getAllDutyPerson(params)
      .then(res => {
        if (res.code === 200 && res.data) {
          // console.log(res, '这是:')
          optionsName.value = res.data.map(item => {
            return {
              id: item.id,
              label: item.name,
              value: item.name
            }
          })
          console.log(optionsName.value, '人员')
        }
      })
      .catch(error => {
        reject(error)
      })
  })
}
onMounted(() => {
  getAllDutyPersonData()
})

2.获取每天值班人

这个步骤应该是上述方案之前的,在开发时记得先做这个步骤,然后再开始获取下拉框的数据。因为这个步骤没做好页面上是啥也看不到的,接下来我们就开始吧

<script setup>
import { ref, getCurrentInstance, onMounted, computed } from 'vue'
import { getAllDutyPerson, getMonthDutyPerson, modifyDutyPerson } from '@/api/schedule-write.js'
const dayList = ref([])
// 当前年月入参
const yearMonthPara = ref(dayjs().format('YYYY-MM'))
//当前月份的天数
const currentMonth = ref(dayjs().month())
//当前年份
const currentYear = ref(dayjs().year())
//处理当前月份天数和当前年份
const daysInMonth = ref(dayjs(`${currentYear}-${currentMonth + 1}-01`).daysInMonth())
const dayOption = ref(
  Array.from({ length: daysInMonth }, (_, index) => ({
    name: '',
    date: dayjs(`${currentYear}-${currentMonth + 1}-${index + 1}`).format('YYYY-MM-DD')
  }))
)
//获取当前月份所有值班人员
const getMonthDutyPersonData = params => {
  return new Promise((resolve, reject) => {
    getMonthDutyPerson(params)
      .then(res => {
        if (res.code === 200 && res.data) {
          // console.log(res, '当月:')
          const mergedList = []
          // 遍历 dayOption 数组
          dayOption.value.forEach(dayOpt => {
            const matchedData = res.data.find(dataItem => {
              return dayOpt.date === dataItem.date
            })
            mergedList.push({
              ...dayOpt,
              ...(matchedData ? { name: matchedData.name } : { name: '' }),
              ...(matchedData ? { id: matchedData.id } : {})
            })
          })
          // 将合并后的数组赋值给 dayList.value
          dayList.value = mergedList
          console.log(dayList.value, '当月值班人员')
        }
      })
      .catch(error => {
        reject(error)
      })
  })
}
onMounted(() => {
  getMonthDutyPersonData(yearMonthPara.value)
})

3.处理选择每个年份、月份所对应的周期及天数

做完了以上的东西后,我们就可以在页面中看到日历了,但是在选择每个年份和月份后我们会发现下面所对应的天数一直都是当月的天数,比如我当前月份是一月,有三十一天,但是我在选择2月份后他的天数依旧31天,但实际上2月份只有28天,另外他的每个一号都是对应在周一,其实这是不对的,存在一定的bug。接下来就来解决这个问题。

<script setup>
import { ref, getCurrentInstance, onMounted, computed } from 'vue'
import { getAllDutyPerson, getMonthDutyPerson, modifyDutyPerson } from '@/api/schedule-write.js'
// 定义一个函数来获取指定日期的第一天是星期几
const getWeekdayOfFirstDay = date => {
  const firstDayOfMonth = dayjs(date).startOf('month')
  return firstDayOfMonth.day() // 返回星期几(0-6,0表示星期日)
}
// 定义一个函数来获取指定日期的最后一天是星期几
const getCurrentCal = () => {
  currentMonth.value = dayjs().month()
  currentYear.value = dayjs().year()
  daysInMonth.value = dayjs(`${currentYear.value}-${currentMonth.value + 1}-01`).daysInMonth()
  dayOption.value = Array.from({ length: daysInMonth.value }, (_, index) => ({
    name: '',
    date: dayjs(`${currentYear.value}-${currentMonth.value + 1}-${index + 1}`).format('YYYY-MM-DD')
  }))

  const specifiedDate = ref(`${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}-01`)
  // 使用 Day.js 解析日期并获取该月份的第一天
  const firstDayOfMonth = dayjs(specifiedDate.value).startOf('month').format('YYYY-MM-DD')
  console.log(firstDayOfMonth, '获取该月份的第一天')
  if (dayOfWeekFirst.value == 0) {
    dayOfWeekFirst.value = 7
  }
  dayOfWeekFirst.value = getWeekdayOfFirstDay(firstDayOfMonth)
  console.log(dayOfWeekFirst.value, '获取该月份的第一天是星期几')
}
onMounted(() => {
  getCurrentCal()
})

以上的问题写了一个解决方法,我们还需要再点击选择年份和月份的点击事件中进行修改

//选择年份
const handleYearChange = val => {
  console.log(val, '选择年份')
  year.value = val
  currentYear.value = parseInt(year.value.toString().slice(0, 4))
  currentMonth.value = parseInt(month.value.toString().slice(0, 2)) - 1
  daysInMonth.value = dayjs(`${currentYear.value}-${currentMonth.value + 1}-01`).daysInMonth()
  dayOption.value = Array.from({ length: daysInMonth.value }, (_, index) => ({
    name: '',
    date: dayjs(`${currentYear.value}-${currentMonth.value + 1}-${index + 1}`).format('YYYY-MM-DD')
  }))
  console.log(dayOption.value, '所选当月的日期~~~选择年份')

  const specifiedDate = ref(`${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}-01`)
  // const specifiedDate = ref('2025-04-15');
  // 使用 Day.js 解析日期并获取该月份的第一天
  const firstDayOfMonth = dayjs(specifiedDate.value).startOf('month').format('YYYY-MM-DD')
  console.log(firstDayOfMonth, '获取该月份的第一天')
  dayOfWeekFirst.value = getWeekdayOfFirstDay(firstDayOfMonth)
  if (dayOfWeekFirst.value == 0) {
    dayOfWeekFirst.value = 7
  }

  yearMonthPara.value = `${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}`
  console.log(yearMonthPara.value, '年月')
//这里需要调用次方法
  getMonthDutyPersonData(yearMonthPara.value)
}
//选择月份
const handleMonthChange = val => {
  console.log(val, '选择月份')
  month.value = val

  currentYear.value = parseInt(year.value.toString().slice(0, 4))
  currentMonth.value = parseInt(month.value.toString().slice(0, 2)) - 1
  daysInMonth.value = dayjs(`${currentYear.value}-${currentMonth.value + 1}-01`).daysInMonth()
  dayOption.value = Array.from({ length: daysInMonth.value }, (_, index) => ({
    name: '',
    date: dayjs(`${currentYear.value}-${currentMonth.value + 1}-${index + 1}`).format('YYYY-MM-DD')
  }))
  console.log(dayOption.value, '所选当月的日期~~~选择年份')

  const specifiedDate = ref(`${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}-01`)
  // const specifiedDate = ref('2025-04-15');
  // 使用 Day.js 解析日期并获取该月份的第一天
  const firstDayOfMonth = dayjs(specifiedDate.value).startOf('month').format('YYYY-MM-DD')
  console.log(firstDayOfMonth, '获取该月份的第一天')
  dayOfWeekFirst.value = getWeekdayOfFirstDay(firstDayOfMonth)
  if (dayOfWeekFirst.value == 0) {
    dayOfWeekFirst.value = 7
  }

  yearMonthPara.value = `${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}`
  getMonthDutyPersonData(yearMonthPara.value)
}

接下来还需要修改的一个地方就是样式的绑定

<div class="canlder-dayList">
    <div
      class="item-list"
      :style="index === 0 ? `margin-left: ${(dayOfWeekFirst - 1) * 6.6}vw` : ''"
      v-for="(item, index) in dayList"
      :key="index"
    >
      <!-- <div class="name name-color">{{ item.name }}</div> -->
      <t-select
        v-model="item.name"
        clearable
        size="medium"
        @change="handleStuffChange($event, index)"
        :options="optionsName"
        class="name name-color"
      />
      <!-- <div class="number number-color">{{ item.date.slice(8, 10) }}</div> -->
      <div class="number number-color">{{ dayjs(item.date).format('DD') }}</div>
    </div>
  </div>
// 每个月的第一天
const dayOfWeekFirst = ref(0)

五、全部代码、效果展示

综上实现可编辑日历的具体步骤就结束了,下面附上全部代码

<template>
  <div class="middle-content">
    <div class="calender-top">
      <t-select
        v-model="year"
        :options="optionsYear"
        clearable
        size="medium"
        @change="handleYearChange"
        style="width: 5vw; margin-right: 1vw"
      />
      <t-select
        v-model="month"
        :options="optionsMonth"
        clearable
        size="medium"
        @change="handleMonthChange"
        style="width: 5vw; margin-right: 1vw"
      />
    </div>
    <ul class="canlder-weekList">
      <li class="item-top" v-for="(item, index) in optionWeek" :key="index">
        <h1>{{ item.label }}</h1>
      </li>
    </ul>
    <div class="canlder-dayList">
      <div
        class="item-list"
        :style="index === 0 ? `margin-left: ${(dayOfWeekFirst - 1) * 6.6}vw` : ''"
        v-for="(item, index) in dayList"
        :key="index"
      >
        <!-- <div class="name name-color">{{ item.name }}</div> -->
        <t-select
          v-model="item.name"
          clearable
          size="medium"
          @change="handleStuffChange($event, index)"
          :options="optionsName"
          class="name name-color"
        />
        <!-- <div class="number number-color">{{ item.date.slice(8, 10) }}</div> -->
        <div class="number number-color">{{ dayjs(item.date).format('DD') }}</div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, getCurrentInstance, onMounted, computed } from 'vue'
import { monthList, weekList } from '@/utils/year-month.js'
import { getAllDutyPerson, getMonthDutyPerson, modifyDutyPerson } from '@/api/schedule-write.js'
const context = getCurrentInstance()?.appContext.config.globalProperties
const dayjs = context?.$dayjs
//当前年份
const year = ref(dayjs().format('YYYY年'))
//当前月份
const month = ref(dayjs().format('MM月'))
// 当前年月入参
const yearMonthPara = ref(dayjs().format('YYYY-MM'))
//所有年份
const optionsYear = ref([])
//所有月份
const optionsMonth = ref([])
//所有星期
const optionWeek = ref([])
// 每个月的第一天
const dayOfWeekFirst = ref(0)
// 当前月份的天数
const currentMonth = ref(dayjs().month())
// 当前年份
const currentYear = ref(dayjs().year())
// 当前月份的天数
const daysInMonth = ref(dayjs(`${currentYear}-${currentMonth + 1}-01`).daysInMonth())
const dayOption = ref(
  Array.from({ length: daysInMonth }, (_, index) => ({
    name: '',
    date: dayjs(`${currentYear}-${currentMonth + 1}-${index + 1}`).format('YYYY-MM-DD')
  }))
)

const dayList = ref([])
//所有人员
const optionsName = ref([])
//选择年份
const handleYearChange = val => {
  console.log(val, '选择年份')
  year.value = val
  currentYear.value = parseInt(year.value.toString().slice(0, 4))
  currentMonth.value = parseInt(month.value.toString().slice(0, 2)) - 1
  daysInMonth.value = dayjs(`${currentYear.value}-${currentMonth.value + 1}-01`).daysInMonth()
  dayOption.value = Array.from({ length: daysInMonth.value }, (_, index) => ({
    name: '',
    date: dayjs(`${currentYear.value}-${currentMonth.value + 1}-${index + 1}`).format('YYYY-MM-DD')
  }))
  console.log(dayOption.value, '所选当月的日期~~~选择年份')

  const specifiedDate = ref(`${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}-01`)
  // const specifiedDate = ref('2025-04-15');
  // 使用 Day.js 解析日期并获取该月份的第一天
  const firstDayOfMonth = dayjs(specifiedDate.value).startOf('month').format('YYYY-MM-DD')
  console.log(firstDayOfMonth, '获取该月份的第一天')
  dayOfWeekFirst.value = getWeekdayOfFirstDay(firstDayOfMonth)
  if (dayOfWeekFirst.value == 0) {
    dayOfWeekFirst.value = 7
  }

  yearMonthPara.value = `${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}`
  console.log(yearMonthPara.value, '年月')
  getMonthDutyPersonData(yearMonthPara.value)
}
//选择月份
const handleMonthChange = val => {
  console.log(val, '选择月份')
  month.value = val

  currentYear.value = parseInt(year.value.toString().slice(0, 4))
  currentMonth.value = parseInt(month.value.toString().slice(0, 2)) - 1
  daysInMonth.value = dayjs(`${currentYear.value}-${currentMonth.value + 1}-01`).daysInMonth()
  dayOption.value = Array.from({ length: daysInMonth.value }, (_, index) => ({
    name: '',
    date: dayjs(`${currentYear.value}-${currentMonth.value + 1}-${index + 1}`).format('YYYY-MM-DD')
  }))
  console.log(dayOption.value, '所选当月的日期~~~选择年份')

  const specifiedDate = ref(`${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}-01`)
  // 使用 Day.js 解析日期并获取该月份的第一天
  const firstDayOfMonth = dayjs(specifiedDate.value).startOf('month').format('YYYY-MM-DD')
  console.log(firstDayOfMonth, '获取该月份的第一天')
  dayOfWeekFirst.value = getWeekdayOfFirstDay(firstDayOfMonth)
  if (dayOfWeekFirst.value == 0) {
    dayOfWeekFirst.value = 7
  }

  yearMonthPara.value = `${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}`
  getMonthDutyPersonData(yearMonthPara.value)
}
//选择人员
const handleStuffChange = (event, itemIndex) => {
  const selectedValue = event
  console.log(selectedValue, '选择人员')
  const selectedOption = optionsName.value.find(option => option.value === selectedValue)
  console.log(selectedOption, '所选人员')
  dayList.value[itemIndex].name = selectedOption.label
  dayList.value[itemIndex].id = selectedOption.id
}

// 生成年份数组的函数
const generateYears = (startYear, endYear) => {
  const years = []
  for (let i = startYear; i <= endYear; i++) {
    years.push({
      label: `${i}年`,
      value: i
    })
  }
  return years
}
//获取当前年份-月份的数据
const getYearData = () => {
  //当前年份
  const currentYear = dayjs().year()
  // 过去的年份数量
  const pastYears = 30
  // 未来的年份数量
  const futureYears = 50
  optionsYear.value = generateYears(currentYear - pastYears, currentYear + futureYears)
  // console.log(optionsYear.value, '年份')
  optionsMonth.value = monthList
  optionWeek.value = weekList
}
//获取所有值班人员--下拉框
const getAllDutyPersonData = params => {
  return new Promise((resolve, reject) => {
    getAllDutyPerson(params)
      .then(res => {
        if (res.code === 200 && res.data) {
          // console.log(res, '这是:')
          optionsName.value = res.data.map(item => {
            return {
              id: item.id,
              label: item.name,
              value: item.name
            }
          })
          console.log(optionsName.value, '人员')
        }
      })
      .catch(error => {
        reject(error)
      })
  })
}
//获取当前月份所有值班人员
const getMonthDutyPersonData = params => {
  return new Promise((resolve, reject) => {
    getMonthDutyPerson(params)
      .then(res => {
        if (res.code === 200 && res.data) {
          const mergedList = []
          // 遍历 dayOption 数组
          dayOption.value.forEach(dayOpt => {
            const matchedData = res.data.find(dataItem => {
              return dayOpt.date === dataItem.date
            })
            mergedList.push({
              ...dayOpt,
              ...(matchedData ? { name: matchedData.name } : { name: '' }),
              ...(matchedData ? { id: matchedData.id } : {})
            })
          })
          // 将合并后的数组赋值给 dayList.value
          dayList.value = mergedList
          console.log(dayList.value, '当月值班人员')
        }
      })
      .catch(error => {
        reject(error)
      })
  })
}

// 定义一个函数来获取指定日期的第一天是星期几
const getWeekdayOfFirstDay = date => {
  const firstDayOfMonth = dayjs(date).startOf('month')
  return firstDayOfMonth.day() // 返回星期几(0-6,0表示星期日)
}
// 获取当前月份的第一天
const getCurrentCal = () => {
  currentMonth.value = dayjs().month()
  currentYear.value = dayjs().year()
  daysInMonth.value = dayjs(`${currentYear.value}-${currentMonth.value + 1}-01`).daysInMonth()
  dayOption.value = Array.from({ length: daysInMonth.value }, (_, index) => ({
    name: '',
    date: dayjs(`${currentYear.value}-${currentMonth.value + 1}-${index + 1}`).format('YYYY-MM-DD')
  }))

  const specifiedDate = ref(`${year.value.toString().slice(0, 4)}-${month.value.toString().slice(0, 2)}-01`)
  // 使用 Day.js 解析日期并获取该月份的第一天
  const firstDayOfMonth = dayjs(specifiedDate.value).startOf('month').format('YYYY-MM-DD')
  console.log(firstDayOfMonth, '获取该月份的第一天')
  if (dayOfWeekFirst.value == 0) {
    dayOfWeekFirst.value = 7
  }
  dayOfWeekFirst.value = getWeekdayOfFirstDay(firstDayOfMonth)
  console.log(dayOfWeekFirst.value, '获取该月份的第一天是星期几')
}

onMounted(() => {
  getCurrentCal()
  getYearData()
  getAllDutyPersonData()
  getMonthDutyPersonData(yearMonthPara.value)
})
</script>

<style lang="less" scoped>
.middle-content {
  width: 49vw;
  height: 88vh;
  overflow: auto;
  margin: 0 0.5vw;
  border-radius: 4px;
  border: 1px solid #e5e5e5;
  box-shadow: 0 0 10px 0 rgba(232, 232, 232, 0.55) inset;
  // display: flex;
  // flex-direction: column;
  // align-items: center;
  &::-webkit-scrollbar {
    width: 5px;
  }
  /*定义滚动条轨道*/
  &::-webkit-scrollbar-track {
    border-radius: 5px;
  }
  /*定义滑块*/
  &::-webkit-scrollbar-thumb {
    border-radius: 5px;
    background: #a8a8a8;
  }

  .calender-top {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: 1vw 0;
    :deep .t-popup__content {
      width: 5vw !important;
    }
    :deep .t-input__inner {
      text-align: center;
      font-size: 0.8vw;
    }
  }
  .canlder-weekList {
    display: flex;
    align-items: center;
    // justify-content: space-between;
    // padding: 0 1vw;
    padding: 0.5vw 0 0 1vw;
    .item-top {
      // display: flex;
      width: 6vw;
      margin: 1vw 0.6vw 0 0;

      h1 {
        text-align: center;
        font-size: 1.2vw;
        font-weight: 500;
        color: #333;
      }
    }
  }
  .canlder-dayList {
    // width: 15%;
    display: flex;
    // flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    flex-wrap: wrap;
    padding: 0.5vw 0 0 0.8vw;
    .item-list {
      width: 6vw;
      margin: 1vw 0.6vw 0 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      .name,
      .number {
        width: 5vw;
        height: 2.5vw;
        font-size: 0.8vw;
        line-height: 2.5vw;
        text-align: center;
      }
      .name-color {
        color: #333;
        background-color: #d8d8d8;
        // background-color: rgb(216, 250, 200);
      }
      .number-color {
        color: #fff;
        background-color: rgb(116, 159, 178);
        // background-color: rgb(138, 189, 114);
      }
      :deep .t-input {
        // background-color: rgb(216, 250, 200);
        background-color: #d8d8d8;
      }
      :deep .t-input__inner {
        font-size: 0.8vw;
        text-align: center;
      }
    }
  }
  .btn-box {
    display: flex;
    // align-items: center;
    justify-content: center;
    align-items: center;
    margin-top: 20px;
    .btn {
      width: 5vw;
      height: 4vh;
      background: #0289c2;
      border-color: #0289c2;
      color: #fff;
    }
    .btn-reset {
      margin-left: 1vw;
      background: #e7e7e7;
      border-color: #e7e7e7;
      color: #393939;
    }
    :deep .t-button__text {
      font-size: 0.8vw;
    }
  }
}
</style>


http://www.kler.cn/a/471789.html

相关文章:

  • 概率论与数理统计--期末
  • 第21章 汇编语言--- DMA(直接内存访问)
  • A second-price auction
  • MySQL 间隙锁避免“可重复读”出现“幻读”
  • OpenCV在现代社会中的应用
  • 【机器学习:四、多输入变量的回归问题】
  • MySQL 如何赶上 PostgreSQL 的势头?
  • 特种设备安全管理人员免费题库限时练习(判断题)
  • NVIDIA在CES 2025上的三大亮点:AI芯片、机器人与自动驾驶、全新游戏显卡
  • [创业之路-241]:《从偶然到必然-华为研发投资与管理实践》-2- IPD流程中的业务线、技术线、职能支撑线
  • 【STM32】I2C为什么要开漏输出和上拉电阻
  • [微服务]redis主从集群搭建与优化
  • 前端 动图方案
  • 【Axure高保真原型】环形进度条(开始暂停效果)
  • 装修房子,你会选购灯和搭配灯光吗?
  • 【竞技宝】CS2:HLTV2024职业选手排名TOP8-broky
  • 智能座舱︱AUTO TECH China 2025广州国际汽车智能座舱及车载显示技术展览会于11月盛大开幕
  • 【网络云SRE运维开发】2025第2周-每日【2025/01/07】小测-【第7章 GVRP链路捆绑】理论和实操解析
  • Qt 5.14.2 学习记录 —— 삼 初级认识
  • 【Ubuntu】想知道怎么通过命令行查看笔记本电池健康程度吗?