Files
smartride-frontend-uniapp/src/pages/classroom/course.vue
2024-11-11 11:08:47 +08:00

311 lines
9.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { onShow } from '@dcloudio/uni-app'
import FullCalendar from '@fullcalendar/vue3'
import timeGridPlugin from '@fullcalendar/timegrid'
import interactionPlugin from '@fullcalendar/interaction'
import listPlugin from '@fullcalendar/list'
import dayjs from 'dayjs'
import { onMounted, ref } from 'vue'
import type {
CalendarOptions,
} from '@fullcalendar/core'
import cusSelects from '~/components/cus-selects-fan.vue'
import { usePageStore } from '~/stores/modules/page'
import { useAppStore } from '~/stores/modules/app'
import { type BuildInfo, type ClassroomCourseInfo, type ClassroomInfo, getBuildListAPI, getClassroomCourseListAPI, getClassroomListAPI } from '~/services/course'
const { startDate, campusList, campusId, buildId, classroomId } = storeToRefs(useAppStore())
const { setPageConfig } = usePageStore()
onShow(() => {
setPageConfig({
showNavBar: true,
pageTitle: '教室课表',
showBackAction: true,
})
})
// #ifdef H5
const campus = ref('')
const buildList = ref<BuildInfo[]>([])
const classroomList = ref<ClassroomInfo[]>([])
const getClassroomList = async () => {
if (buildId.value) {
uni.showLoading({ title: '加载中~' })
const res = await getClassroomListAPI(buildId.value)
if (res.code === 200)
classroomList.value = res.data
uni.hideLoading()
uni.showToast({ icon: res.code === 200 ? 'success' : 'error', title: res.msg })
}
}
const getBuildList = async () => {
if (campusId.value) {
uni.showLoading({ title: '加载中~' })
const res = await getBuildListAPI(campus.value)
if (res.code === 200)
buildList.value = res.data
uni.hideLoading()
uni.showToast({ icon: res.code === 200 ? 'success' : 'error', title: res.msg })
}
}
const onCampusSelectChange = async (e: string) => {
campus.value = e
await getBuildList()
}
const onBuildSelectChange = async (e: string) => {
buildId.value = e
await getClassroomList()
}
/** 当前事件列表 */
const currentEvents = ref([])
/** 日历对象 */
const fullCalendar = ref()
const courseList = ref<ClassroomCourseInfo[]>([])
const getClassroomCourses = async () => {
const startTime = dayjs(startDate.value).unix()
// const start = dayjs(fullCalendar.value.getApi().view.activeStart).unix()
const endTime = dayjs(fullCalendar.value.getApi().view.activeEnd).unix()
const week = Math.floor((endTime - startTime) / (60 * 60 * 24 * 7))
if (classroomId.value) {
const res = await getClassroomCourseListAPI(classroomId.value, week)
if (res.code === 200) {
courseList.value = res.data
if (res.data) {
fullCalendar.value.getApi().removeAllEvents() // 清除所有事件
currentEvents.value = courseList.value.map(data => ({
id: data.id,
title: `${data.course} - ${data.teacher}`,
start: data.startTime.replace('T', ' ').replace('Z', ''),
end: data.endTime.replace('T', ' ').replace('Z', ''),
extendedProps: {
classnames: data.classnames,
campus: data.campus,
build: data.build,
},
}))
fullCalendar.value.getApi().addEventSource(currentEvents.value) // 添加新的事件源
}
}
fullCalendar.value.getApi().render() // 手动刷新日历
}
}
const onClassroomSelectChange = async (e: string) => {
classroomId.value = e
await getClassroomCourses()
}
/** 自定义上周按钮点击事件 */
const preWeekCustomClick = async () => {
fullCalendar.value.getApi().prev() // 切换到上一周
await getClassroomCourses()
}
/** 自定义下周按钮点击事件 */
const nextWeekCustomClick = async () => {
fullCalendar.value.getApi().next()
await getClassroomCourses()
}
/** 日历组件属性 */
const calendarOptions = ref<CalendarOptions>({
// 插件
plugins: [
listPlugin, // 列表视图插件
timeGridPlugin, // 周视图和日视图插件
interactionPlugin, // 交互插件,支持点击事件
],
// 自定义按钮
customButtons: {
preWeekCustom: {
text: '上周',
click() {
preWeekCustomClick() // 点击调用 preWeekCustomClick 函数
},
},
nextWeekCustom: {
text: '下周',
click() {
nextWeekCustomClick() // 点击调用 nextWeekCustomClick 函数
},
},
},
/** 修改headerToolbar */
headerToolbar: {
left: 'preWeekCustom',
center: 'title', // 显示日历标题
right: 'nextWeekCustom',
},
dayHeaderFormat: {
weekday: 'short', // 显示周几,如"周日"
month: '2-digit', // 显示两位数的月份
day: '2-digit', // 显示两位数的日期
omitCommas: true, // 去除逗号
},
/** 设置日历高度 */
contentHeight: uni.getWindowInfo().windowHeight - 260, // 动态计算高度
timeZone: 'Asia/Shanghai',
/** 默认视图 (月:dayGridMonth,周:timeGridWeek,日:timeGridDay) */
initialView: 'timeGridWeek', // 默认显示周视图
firstDay: 1, // 一周的第一天0表示星期天1表示星期一
slotMinTime: '08:00', // 最小时间段08:00
slotMaxTime: '22:10', // 最大时间段22:10
slotDuration: '00:05', // 时间间隔5分钟
slotLabelFormat: {
hour: '2-digit',
minute: '2-digit',
omitZeroMinute: false, // 忽略零分钟
hour12: false, // 24小时制
meridiem: 'short',
},
eventTimeFormat: {
hour: '2-digit',
minute: '2-digit',
hour12: false, // 24小时制
},
eventColor: '#3BB2E3', // 全部日历日程背景色
themeSystem: 'bootstrap', // 主题色(本地测试未能生效)
events: currentEvents.value, // 事件列表
editable: false, // 是否可以拖动修改事件
allDaySlot: false, // 是否显示全天事件区域
nowIndicator: true, // 是否显示当前时间线
selectable: true, // 是否可以选择时间段
selectMirror: true, // 是否在选择时间段时显示虚影
handleWindowResize: true, // 是否在窗口大小变化时调整日历
navLinks: false, // 是否可以通过点击日期导航
fixedWeekCount: true, // 每月显示固定周数
showNonCurrentDates: true, // 是否显示非当前月的日期
dayMaxEvents: true, // 每天最大事件数,超过则显示更多按钮
weekends: true, // 是否显示周末
/** 切换语言 */
locale: 'zh-cn', // 语言设置为简体中文
buttonText: {
today: '今天',
week: '周视图',
day: '日',
list: '周列表',
},
})
onMounted(async () => {
campus.value = campusId.value
await getBuildList()
await getClassroomList()
await getClassroomCourses()
fullCalendar.value.getApi().render()
})
// #endif
</script>
<template>
<!-- #ifdef H5 -->
<UBasePage>
<view class="query-select">
<view class="query-select-item">
<view class="query-select-item-left">
<uni-icons type="map" color="#A0E2AA" size="24" />
<text>校区</text>
</view>
<view>
<cus-selects
:value="campus"
filterable
:data="campusList"
:value-type="{ label: 'name', value: 'id' }"
placeholder="请选择校区~"
style="width: 100%"
@change="onCampusSelectChange"
/>
</view>
</view>
<view class="query-select-item">
<view class="query-select-item-left">
<uni-icons type="home" color="#F9BD56" size="24" />
<text>教学楼</text>
</view>
<view>
<cus-selects
:value="buildId"
filterable
:data="buildList"
:value-type="{ label: 'name', value: 'id' }"
placeholder="请选择教学楼~"
style="width: 100%"
@change="onBuildSelectChange"
/>
</view>
</view>
<view class="query-select-item">
<view class="query-select-item-left">
<uni-icons type="location" color="#FEC2BF" size="24" />
<text>教室</text>
</view>
<view>
<cus-selects
:value="classroomId"
filterable
:data="classroomList"
:value-type="{ label: 'name', value: 'id' }"
placeholder="请选择教室~"
style="width: 100%"
@change="onClassroomSelectChange"
/>
</view>
</view>
</view>
<FullCalendar ref="fullCalendar" :options="calendarOptions">
<template #eventContent="arg">
<view class="calender-content">
{{ arg.timeText }}
</view>
<view class="calender-content">
{{ arg.event.title }}
</view>
<view class="calender-content">
上课班级数量: {{ arg.event.extendedProps.classnames.length }}
</view>
</template>
</FullCalendar>
</UBasePage>
<!-- #endif -->
<!-- #ifndef H5 -->
<web-view src="/hybrid/html/calender.html" :fullscreen="false" style="width: 100%; height: 500px;" />
<!-- #endif -->
</template>
<style lang="scss">
.query-select{
padding: 10rpx 20rpx;
background-image: linear-gradient(-225deg, #FFFEFF 0%, #D7FFFE 100%);
.query-select-item{
border-bottom: 2rpx solid #e9e9e9;
padding: 10rpx 0;
display: flex;
justify-content: space-between;
align-items: center;
.query-select-item-left {
width: 30%;
text {
margin-left: 5rpx;
color: #29a1f7;
}
}
}
}
.calender-content{
text-align: center;
}
:deep(.fc .fc-toolbar-title){
font-size: 30rpx;
}
:deep(.fc){
font-size: 26rpx;
}
:deep(.fc .fc-toolbar.fc-header-toolbar){
margin-bottom: 10rpx;
}
</style>