taskCalendar.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. <template>
  2. <div class="w-full h-full flex flex-col calendarPlugin">
  3. <div class="flex-1" v-loading="calendarLoading">
  4. <FullCalendar ref="calendarRef" :options="calendarOptions" class="h-full w-full">
  5. <template v-slot:eventContent='arg'>
  6. <div>{{ arg.event.title }}</div>
  7. </template>
  8. </FullCalendar>
  9. </div>
  10. </div>
  11. </template>
  12. <script setup lang="ts">
  13. import { ref, onMounted } from 'vue';
  14. import FullCalendar from '@fullcalendar/vue3';
  15. import dayGridPlugin from '@fullcalendar/daygrid';
  16. import timeGridPlugin from '@fullcalendar/timegrid'
  17. import interactionPlugin from '@fullcalendar/interaction'
  18. import zhCnLocale from '@fullcalendar/core/locales/zh-cn'
  19. import { post, uploadFile } from '@/utils/request';
  20. import { GET_TASK_LIST_BY_START_AND_END } from './api'
  21. import { formatDate, getFirstDayOfMonth, getLastDayOfMonth } from '@/utils/times';
  22. import { dayjs } from 'element-plus';
  23. // 当前选中的视图
  24. const currentView = ref('dayGridMonth')
  25. // 日历实例引用
  26. const calendarRef = ref()
  27. const dateForm = ref({
  28. startDate: getFirstDayOfMonth(new Date()),
  29. endDate: getLastDayOfMonth(new Date())
  30. })
  31. const calendarListData = ref([])
  32. const calendarLoading = ref(false)
  33. // FullCalendar 配置
  34. const calendarOptions = ref<any>({
  35. plugins: [dayGridPlugin, timeGridPlugin, interactionPlugin],
  36. locale: zhCnLocale,
  37. initialView: currentView.value,
  38. slotMinTime: '06:00:00', // 最早显示时间
  39. slotMaxTime: '22:00:00', // 最晚显示时间
  40. slotDuration: '01:00:00', // 一个小时一格(timeGrid生效)
  41. events: [],
  42. headerToolbar: { // 自定义头部
  43. left: 'today,prev,next', // 左侧按钮:上一页,下一页,今天
  44. center: 'title',
  45. right: 'dayGridMonth,timeGridWeek,timeGridDay' // 右侧显示视图切换按钮
  46. },
  47. slotLabelContent: (arg: any) => {
  48. const hour = arg.date.getHours()
  49. const meridiem = hour < 12 ? '上午' : '下午'
  50. return `${meridiem} ${hour} 时`
  51. },
  52. datesSet: (arg: any) => { // 📌 每次切换视图或日期都会触发
  53. const { startStr = '', endStr = '' } = arg
  54. if (startStr && endStr) {
  55. dateForm.value = {
  56. startDate: startStr,
  57. endDate: endStr,
  58. }
  59. getTaskCalendar()
  60. }
  61. }
  62. })
  63. // 重新渲染表格数据
  64. function renderTableData() {
  65. calendarOptions.value = {
  66. ...calendarOptions.value,
  67. events: (calendarListData.value || []).map((item: any) => {
  68. return {
  69. ...item,
  70. start: item.startDate,
  71. end: item.endDate,
  72. title: item.taskName,
  73. // backgroundColor: ['#909399', '#075985', '#67C23A', '#F56C6C'][item.status],
  74. // borderColor: ['#909399', '#075985', '#67C23A', '#F56C6C'][item.status]
  75. backgroundColor: ['#a6a9b0', '#3a7fc1', '#7fbf72', '#e28c8c'][item.status],
  76. borderColor: ['#a6a9b0', '#3a7fc1', '#7fbf72', '#e28c8c'][item.status],
  77. }
  78. })
  79. }
  80. }
  81. function getTaskCalendar() {
  82. const { startDate, endDate } = dateForm.value
  83. calendarLoading.value = true
  84. post(GET_TASK_LIST_BY_START_AND_END, {
  85. startDate: dayjs(startDate).format('YYYY-MM-DD'),
  86. endDate: dayjs(endDate).format('YYYY-MM-DD')
  87. }).then((res) => {
  88. calendarListData.value = res.data || []
  89. renderTableData()
  90. }).finally(() => {
  91. calendarLoading.value = false
  92. })
  93. }
  94. onMounted(() => {
  95. getTaskCalendar()
  96. })
  97. defineExpose({
  98. getTaskCalendar
  99. })
  100. </script>
  101. <style lang="scss" scoped>
  102. .calendarPlugin {
  103. :deep(.fc-today-button) {
  104. margin-right: 10px;
  105. }
  106. :deep(table) {
  107. height: 100%;
  108. }
  109. /* 强制事件内文字换行 */
  110. :deep(.fc-timegrid-col-events .fc-event-main) div {
  111. width: 50%;
  112. white-space: normal !important;
  113. word-break: break-word;
  114. }
  115. :deep(.fc-timegrid-col-events .fc-timegrid-event-harness:last-child .fc-event-main) div {
  116. width: 100%;
  117. white-space: normal !important;
  118. word-break: break-word;
  119. }
  120. }
  121. </style>