v2.4.0 patch2
Build and publish Jiaowu packages and container image / Test, package and publish (push) Successful in 41m12s
Build and publish Jiaowu packages and container image / Test, package and publish (push) Successful in 41m12s
This commit is contained in:
@@ -8,25 +8,43 @@ const type = computed(() => route.params.type as 'classroom' | 'building')
|
||||
const id = computed(() => route.params.id as string)
|
||||
const data = ref<any>()
|
||||
const now = ref(new Date())
|
||||
const page = ref(0)
|
||||
const pageSize = ref(1)
|
||||
let timer = 0
|
||||
let pageTimer = 0
|
||||
const title = computed(() => type.value === 'classroom' ? data.value?.classroom : data.value?.building)
|
||||
const timeText = computed(() => now.value.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', second: '2-digit' }))
|
||||
const displayItems = computed(() => type.value === 'classroom' ? data.value?.entries ?? [] : data.value?.rooms ?? [])
|
||||
const pageCount = computed(() => Math.max(1, Math.ceil(displayItems.value.length / pageSize.value)))
|
||||
const visibleItems = computed(() => displayItems.value.slice(page.value * pageSize.value, (page.value + 1) * pageSize.value))
|
||||
async function load() { data.value = (await http.get(`/venue-displays/${type.value}s/${id.value}`)).data }
|
||||
onMounted(async () => { await load(); timer = window.setInterval(() => { now.value = new Date(); if (now.value.getMinutes() % 5 === 0 && now.value.getSeconds() === 0) void load() }, 1000) })
|
||||
onBeforeUnmount(() => window.clearInterval(timer))
|
||||
function fitPage() {
|
||||
const header = window.innerWidth < 620 ? 220 : 170
|
||||
const available = Math.max(1, window.innerHeight - header)
|
||||
if (type.value === 'classroom') {
|
||||
const columns = window.innerWidth >= 1280 ? 3 : window.innerWidth >= 760 ? 2 : 1
|
||||
pageSize.value = Math.max(1, Math.floor(available / 190) * columns)
|
||||
} else pageSize.value = Math.max(1, Math.floor(available / 58))
|
||||
page.value = Math.min(page.value, pageCount.value - 1)
|
||||
}
|
||||
function nextPage() { page.value = (page.value + 1) % pageCount.value }
|
||||
onMounted(async () => { await load(); fitPage(); window.addEventListener('resize', fitPage); timer = window.setInterval(() => { now.value = new Date(); if (now.value.getMinutes() % 5 === 0 && now.value.getSeconds() === 0) void load() }, 1000); pageTimer = window.setInterval(nextPage, 25000) })
|
||||
onBeforeUnmount(() => { window.clearInterval(timer); window.clearInterval(pageTimer); window.removeEventListener('resize', fitPage) })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="venue-display" :class="`venue-${type}`">
|
||||
<header><div><span>明序大学 · 智慧教学空间</span><h1>{{ title?.name ?? '正在加载' }}</h1><p>{{ title?.campusName }} · {{ title?.buildingName ?? title?.code }} · {{ data?.term ?? '当前教学日' }}</p></div><time>{{ timeText }}<small>{{ data?.today }}</small></time></header>
|
||||
<section v-if="type === 'classroom'" class="course-board">
|
||||
<article v-for="entry in data?.entries" :key="`${entry.startPeriod}-${entry.courseName}`"><b>第 {{ entry.startPeriod }}-{{ entry.startPeriod + entry.periodCount - 1 }} 节</b><h2>{{ entry.courseName }}</h2><p>{{ entry.classNames?.join('、') }} · {{ entry.teacherNames?.join('、') }}</p></article>
|
||||
<article v-for="entry in visibleItems" :key="`${entry.startPeriod}-${entry.courseName}`"><b>第 {{ entry.startPeriod }}-{{ entry.startPeriod + entry.periodCount - 1 }} 节</b><h2>{{ entry.courseName }}</h2><p>{{ entry.classNames?.join('、') }} · {{ entry.teacherNames?.join('、') }}</p></article>
|
||||
<div v-if="data && !data.entries?.length" class="empty">今日暂无排课<br><small>此教室可供安排使用</small></div>
|
||||
</section>
|
||||
<section v-else class="room-board"><div class="periods"><span v-for="slot in data?.slots" :key="slot.periodNumber">{{ slot.periodNumber }}<small>{{ slot.startsAt?.slice(0,5) }}</small></span></div><article v-for="room in data?.rooms" :key="room.code"><b>{{ room.name }}</b><span v-for="slot in data?.slots" :key="slot.periodNumber" :class="{ free: room.freePeriods?.includes(slot.periodNumber) }">{{ room.freePeriods?.includes(slot.periodNumber) ? '空闲' : '占用' }}</span></article></section>
|
||||
<section v-else class="room-board"><div class="periods"><span v-for="slot in data?.slots" :key="slot.periodNumber">{{ slot.periodNumber }}<small>{{ slot.startsAt?.slice(0,5) }}</small></span></div><article v-for="room in visibleItems" :key="room.code"><b>{{ room.name }}</b><span v-for="slot in data?.slots" :key="slot.periodNumber" :class="{ free: room.freePeriods?.includes(slot.periodNumber) }">{{ room.freePeriods?.includes(slot.periodNumber) ? '空闲' : '占用' }}</span></article></section>
|
||||
<footer v-if="pageCount > 1"><span v-for="index in pageCount" :key="index" :class="{ active: index - 1 === page }"></span><b>{{ page + 1 }} / {{ pageCount }}</b></footer>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.venue-display{min-height:100vh;padding:clamp(22px,4vw,62px);background:#0b1e2b;color:#eef7f5;font-family:"Microsoft YaHei",sans-serif}.venue-display header{display:flex;justify-content:space-between;gap:28px;padding-bottom:28px;border-bottom:1px solid #315464}.venue-display header span{color:#63d6bc;letter-spacing:.16em;font-size:12px}.venue-display h1{font-size:clamp(32px,5vw,68px);margin:10px 0}.venue-display p{margin:0;color:#abc5cf}.venue-display time{font:clamp(26px,4vw,52px) ui-monospace,monospace;text-align:right;color:#63d6bc}.venue-display time small{display:block;font:13px "Microsoft YaHei";color:#abc5cf;margin-top:8px}.course-board{display:grid;grid-template-columns:repeat(auto-fit,minmax(270px,1fr));gap:18px;margin-top:32px}.course-board article{padding:26px;background:#123243;border-left:5px solid #63d6bc}.course-board b{color:#63d6bc}.course-board h2{font-size:clamp(24px,3vw,40px);margin:24px 0 12px}.empty{grid-column:1/-1;padding:80px 20px;text-align:center;font-size:30px;background:#102a38;color:#63d6bc}.room-board{margin-top:30px;overflow:auto}.periods,.room-board article{display:grid;grid-template-columns:minmax(150px,2fr) repeat(12,minmax(65px,1fr));gap:4px;min-width:950px}.periods{margin-left:0}.periods span{grid-column:span 1;text-align:center;color:#abc5cf}.periods span:first-child{grid-column:1}.periods small{display:block}.room-board article{margin-top:5px}.room-board article b,.room-board article span{padding:16px 8px;background:#213c49;text-align:center}.room-board article span.free{background:#1d6b5d;color:white;font-weight:bold}@media(max-width:620px){.venue-display header{display:block}.venue-display time{text-align:left;margin-top:18px}.venue-display{padding:22px}.course-board article{padding:20px}}
|
||||
.venue-display footer{display:flex;align-items:center;justify-content:center;gap:7px;margin-top:20px;color:#abc5cf}.venue-display footer span{width:7px;height:7px;border-radius:50%;background:#42616d}.venue-display footer span.active{width:22px;border-radius:5px;background:#63d6bc}.venue-display footer b{margin-left:8px;font:12px ui-monospace,monospace}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user