<template>
<view class="calendar-container" style="margin: 20rpx 0; margin-bottom: 0">
<!-- 头部显示 -->
<!-- <view class="header">
<text class="year-month">{{ displayYearMonth }}</text> -->
<!-- <img class="person-img" style="width: 120rpx" :src="IMG_URL + 'schedulePerson.png'" /> -->
<!-- <img width="100%;" style="border-top-left-radius: 32rpx; border-top-right-radius: 32rpx" :src="IMG_URL + 'date-header.png'" /> -->
<view class="fr jb ac" style="margin: 0 40rpx">
<view class="fr jb ac">
<!-- 向左箭头上一周 -->
<image class="arrow-left" v-if="isShowArrowLeft" style="width: 30rpx; height: 30rpx; margin-right: 10rpx; transform: rotate(180deg)" :src="IMG_URL + 'before_icon.png'" @click="handleArrowLeft" />
<image class="arrow-left" v-if="!isShowArrowLeft" style="width: 30rpx; height: 30rpx; margin-right: 10rpx" :src="IMG_URL + 'after_icon.png'" @click="handleArrowLeft" />
<!-- 中间显示日期 -->
<view class="date-change-btn">{{ formattedDate }}</view>
<!-- 向右箭头下一周 -->
<image class="arrow-right" v-if="isShowArrowRight" style="width: 30rpx; height: 30rpx; margin-left: 10rpx" :src="IMG_URL + 'before_icon.png'" @click="handleArrowRight" />
<image class="arrow-right" v-if="!isShowArrowRight" style="width: 30rpx; height: 30rpx; margin-left: 10rpx; transform: rotate(180deg)" :src="IMG_URL + 'after_icon.png'" @click="handleArrowRight" />
</view>
<!-- <view class="fr jb ac" v-if="props.isShow != false">
<view class="date-change-btn">
<image style="width: 40rpx; height: 40rpx; margin-right: 20rpx" :src="IMG_URL + 'filtration.png'" />
</view>
</view> -->
</view>
<!-- 滑动容器 -->
<!-- <swiper :current-item-id="currentItemId" @change="onSwiperChange" class="swiper-container" :duration="300"> -->
<swiper :current-item-id="currentItemId" @change="throttledSwiperChange" class="swiper-container" :duration="300" :circular="false">
<swiper-item v-for="item in weekArray" :key="item" :item-id="item.toString()" class="swiper-item">
<view class="week-container">
<view v-for="day in weekDateObject.obj[item]" :key="day.date" class="day-item" @tap="selectDay(day)">
<text class="weekday">{{ day.weekday }}</text>
<text class="day-number" :class="{ today: day.isToday, current: currentSelected === formatDate1(day.date) }">{{ day.day }}</text>
<!-- <view v-if="dataArray?.includes(formatDate1(day.date))" style="background-color: #ffbd27; width: 6rpx; height: 6rpx; border-radius: 999rpx; margin-top: 4rpx"> </view> -->
<image v-if="dataArray.includes(formatDate1(day.date))" style="width: 10rpx; height: 10rpx; margin-top: 4rpx" :src="IMG_URL + 'star_a.png'" />
</view>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script setup>
import { IMG_URL } from '@/config/base'
import { getCalendarStatistics } from '@/request/api/org/course.js'
import { addWeeks, eachDayOfInterval, endOfWeek, format, isSameDay, isToday, startOfWeek, subWeeks } from 'date-fns'
import { zhCN } from 'date-fns/locale'
import { throttle } from 'lodash-es'
import { computed, ref, watch } from 'vue'
const emit = defineEmits(['date-change'])
// 当前基准日期(中间位置)
const baseDate = ref(new Date())
const currentItemId = ref('0')
const isInitialized = ref(false) // 添加初始化标志
const props = defineProps({
courseId: {
type: String,
default: ''
},
// 兼容c端约课组件
type: {
type: Number,
default: 1
},
function: {
type: Function,
default: null
},
// 兼容c端约课组件
courseMode: {
type: Number,
default: null
},
//插班补课是否显示筛选
isShow: {
type: Boolean,
default: true
}
})
// 预渲染的周数据(前一周/当前周/下一周)
const formatDate1 = dateString => {
const date = new Date(dateString)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
const userInfo = uni.getStorageSync('USERINFO')
const orgId = computed(() => uni.getStorageSync('orgInfo').orgId || {})
// const weekArray = ref([-4, -3, -2, -1, 0, 1, 2, 3, 4])
const weekArray = ref([-1, 0, 1]) // 只保留前一周/当前周/下一周
const dataArray = ref([])
const weekDateObject = computed(() => {
const finallyArray = weekArray.value.map(week => {
let curDate
if (week < 0) {
curDate = subWeeks(baseDate.value, Math.abs(week))
} else if (week == 0) {
curDate = baseDate.value
} else {
curDate = addWeeks(baseDate.value, week)
}
const start = startOfWeek(curDate, { weekStartsOn: 1 })
const end = endOfWeek(curDate, { weekStartsOn: 1 })
return {
[week]: eachDayOfInterval({ start, end }).map(day => ({
date: day,
day: format(day, 'd'),
// 使用自定义函数截取第二个字符(去掉"周"字)
weekday: format(day, 'EEE', { locale: zhCN }).substring(1),
isToday: isToday(day),
isCurrent: isSameDay(day, new Date())
}))
}
})
console.log('finallyArray', finallyArray)
const obj = {}
finallyArray.forEach(item => {
obj[Object.keys(item)[0]] = Object.values(item)[0]
})
const returnObj = {
obj,
startTime: formatDate1(obj[weekArray.value[0]][0].date),
endTime: formatDate1(obj[weekArray.value[weekArray.value.length - 1]][6].date)
}
console.log(obj, 'obj')
return returnObj
})
const getScheduleData = () => {
if (!weekDateObject.value) {
return
}
const params = {
beginTime: `${weekDateObject.value.startTime} 00:00:00`,
endTime: `${weekDateObject.value.endTime} 23:59:59`,
orgId: orgId.value,
userId: userInfo.userId
}
if (props.courseId) {
params.courseId = props.courseId
}
// 兼容c端约课组件
if (props.courseMode) {
params.courseMode = props.courseMode
}
let port = getCalendarStatistics
// 兼容c端约课组件
if (props.type == 1) {
port = getCalendarStatistics
} else {
port = props.function
}
console.log(port, 'port')
port(params).then(res => {
dataArray.value = res.data?.map(v => v.scheduleDate)
// console.log(dataArray.value, "dataArray");
})
}
watch(
() => [weekDateObject.value, props.courseId],
() => {
getScheduleData()
},
{ immediate: true, deep: true }
)
// 判断上一周是否有课表
const isShowArrowLeft = computed(() => {
const prevWeekMonday = format(startOfWeek(subWeeks(baseDate.value, 1), { weekStartsOn: 1 }), 'yyyy-MM-dd')
return dataArray.value.includes(prevWeekMonday)
})
// 判断下一周是否有课表
const isShowArrowRight = computed(() => {
const nextWeekMonday = format(startOfWeek(addWeeks(baseDate.value, 1), { weekStartsOn: 1 }), 'yyyy-MM-dd')
return dataArray.value.includes(nextWeekMonday)
})
const handleArrowLeft = () => {
const { start, end } = getLastWeek()
baseDate.value = subWeeks(baseDate.value, 1)
emit('date-search', start, end)
}
const handleArrowRight = () => {
const { start, end } = getNextWeek()
baseDate.value = addWeeks(baseDate.value, 1)
emit('date-search', start, end)
}
// 新增辅助方法获取日期范围
const getDateRange = date => {
const start = format(startOfWeek(date, { weekStartsOn: 1 }), 'yyyy-MM-dd')
const end = format(endOfWeek(date, { weekStartsOn: 1 }), 'yyyy-MM-dd')
return [start, end]
}
// 重构 onSwiperChange 方法
// const onSwiperChange = e => {
// const curId = Number(e.detail.currentItemId)
// currentItemId.value = curId.toString()
// // 向左滑动加载前一周
// if (curId === weekArray.value[0]) {
// baseDate.value = subWeeks(baseDate.value, 1)
// emit('date-search', ...getDateRange(baseDate.value))
// }
// // 向右滑动加载下一周
// if (curId === weekArray.value[weekArray.value.length - 1]) {
// baseDate.value = addWeeks(baseDate.value, 1)
// emit('date-search', ...getDateRange(baseDate.value))
// }
// }
const onSwiperChange = e => {
const curId = Number(e.detail.currentItemId)
currentItemId.value = curId.toString()
// 如果是初始化阶段,不触发date-search
if (!isInitialized.value) {
isInitialized.value = true
return
}
// 向左滑动加载前一周
if (curId === weekArray.value[0]) {
weekArray.value.unshift(curId - 1)
// 限制最大数量(可选)
if (weekArray.value.length > 10) weekArray.value.pop()
}
// 向右滑动加载下一周
else if (curId === weekArray.value[weekArray.value.length - 1]) {
weekArray.value.push(curId + 1)
// 限制最大数量(可选)
if (weekArray.value.length > 10) weekArray.value.shift()
}
// 触发数据更新
const curDate = addWeeks(baseDate.value, curId)
emit('date-search', ...getDateRange(curDate))
}
// 创建节流版本
const throttledSwiperChange = throttle(onSwiperChange, 300, { leading: true, trailing: false })
// 向左箭头查询上一周课表列表数据
// 获取上一周的开始和结束时间
const getLastWeek = () => {
//时间格式化为YYYY-MM-DD
const lastWeek = subWeeks(baseDate.value, 1)
const start = format(startOfWeek(lastWeek, { weekStartsOn: 1 }), 'yyyy-MM-dd')
const end = format(endOfWeek(lastWeek, { weekStartsOn: 1 }), 'yyyy-MM-dd')
return { start, end }
}
//获取下一周的开始和结束时间
const getNextWeek = () => {
const nextWeek = addWeeks(baseDate.value, 1)
const start = format(startOfWeek(nextWeek, { weekStartsOn: 1 }), 'yyyy-MM-dd')
const end = format(endOfWeek(nextWeek, { weekStartsOn: 1 }), 'yyyy-MM-dd')
return { start, end }
}
// const handleArrowLeft = () => {
// // 先获取时间范围(只调用一次)
// const newId = Math.min(...weekArray.value) - 1
// weekArray.value.unshift(newId)
// currentItemId.value = newId.toString()
// // 发送单个请求
// getCalendarStatistics({
// beginTime: `${start} 00:00:00`,
// endTime: `${end} 23:59:59`,
// orgId: orgId.value,
// userId: userInfo.userId
// }).then(res => {
// formattedDate.value = `${start} - ${end}`
// })
// // 触发父组件更新(只需要触发一次)
// emit('date-search', start, end)
// }
// 向右箭头下一周
// const handleArrowRight = () => {
// // 先获取时间范围(只调用一次)
// const { start, end } = getNextWeek()
// //下一周
// baseDate.value = addWeeks(baseDate.value, 1)
// // 触发父组件更新(只需要触发一次)
// //发送单个请求
// getCalendarStatistics({
// beginTime: `${start} 00:00:00`,
// endTime: `${end} 23:59:59`,
// orgId: orgId.value,
// userId: userInfo.userId
// }).then(res => {
// formattedDate.value = `${start} - ${end}`
// })
// // 触发父组件更新(只需要触发一次)
// emit('date-search', start, end)
// }
const currentSelected = ref(formatDate1(new Date())) // 初始化为字符串格式
// 选择日期
// 修改后的selectDay方法
const selectDay = day => {
currentSelected.value = formatDate1(day.date) // 确保存储字符串格式
emit('date-change', currentSelected.value)
// 调试日志
console.log('当前选中:', currentSelected.value)
console.log('点击日期:', formatDate1(day.date))
}
// 格式化日期取当前日期的一周的开始和结束
const formattedDate = computed(() => {
const currentWeekIndex = currentItemId.value
const currentWeek = weekDateObject.value.obj[currentWeekIndex]
if (!currentWeek) return ''
const monday = currentWeek[0].date
const sunday = currentWeek[6].date
// 格式化日期为 "YYYY年MM月DD日" 格式
const formatDate = date => {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}年${month}月${day}日`
}
// 格式化结束日期为 "MM月DD日" 格式
const formatEndDate = date => {
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${month}月${day}日`
}
return `${formatDate(monday)} - ${formatEndDate(sunday)}`
})
const formatDate = dateString => {
const date = new Date(dateString)
return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日` // 格式化为 YYYY年MM月
// return `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`; // 格式化为 YYYY年MM月DD日
}
</script>
<style scoped>
.calendar-container {
position: relative;
background: #fff;
border-radius: 32rpx;
/* box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); */
}
.header {
padding: 24rpx;
border-bottom: 1rpx solid #eee;
}
.year-month {
font-size: 32rpx;
color: #333;
font-weight: bold;
}
.swiper-container {
/* padding-top: 90rpx; */
height: 180rpx;
}
.swiper-item {
height: 100%;
}
.week-container {
display: flex;
justify-content: space-around;
align-items: center;
padding: 0 20rpx;
gap: 5rpx;
height: 100%;
}
.day-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1; /* 关键修改:等分容器宽度 */
height: 120rpx;
border-radius: 16rpx;
transition: all 0.2s;
font-weight: 500;
color: #4a4a4a;
}
.weekday {
font-size: 20rpx;
color: #4a4a4a;
margin-bottom: 8rpx;
}
.day-number {
font-size: 28rpx;
color: #333;
padding: 0 10rpx;
border-radius: 12rpx;
margin-bottom: 10rpx;
}
/* .current {
background: #5e94ff !important;
color: #fff !important;
border: 1rpx solid #3a6ccc !important;
} */
.today {
background: #83c3ff;
color: #333;
}
.today {
/* background: #83c3ff; */
/* border: 1rpx solid #5e94ff; */
}
/* .today .day-number {
color: #328add;
font-weight: bold;
} */
.current {
background: #5e94ff !important;
color: #fff !important;
}
.current .weekday,
.current .day-number {
color: #fff !important;
}
.date-change-btn {
/* position: absolute;
top: 10rpx;
left: 24rpx; */
/* padding: 0 20rpx; */
font-weight: bold;
font-size: 26rpx;
color: #000000;
line-height: 70rpx;
height: 70rpx;
/* margin-left: 40rpx; */
/* background: #edf6ff; */
border-radius: 20rpx 20rpx 20rpx 20rpx;
}
.person-img {
position: absolute;
right: 60rpx;
top: -128rpx;
width: 200rpx;
}
</style>能不能根据已上代码重新写这个组件,样式布局不变,props的条件不变,就是把滑动日历的功能和点击上一周和下一周这两个共嗯那个每一次改变保持同步可以更改const weekArray = ref([-1, 0, 1]) 的初始值,只要滑动和切换保持一致就可以,
最新发布