- 隐藏页签(cqy)访问后保持可见:路由进入即标记 visited,切走不再消失 - 页签切换默认不卸载组件:<KeepAlive :include> 缓存全部模块组件 仅声明 requiresAlive 的模块在服务失活(down)时移出 include -> 卸载 - 白板存活检测改为加载即探测 + 每 30s 周期重探(startPolling), 状态在 up/down 间响应式翻转,不再一次性固化 - 各模块组件 defineOptions name 与模块 id 一致,便于 KeepAlive 精确匹配
106 lines
2.7 KiB
Vue
106 lines
2.7 KiB
Vue
<script setup>
|
||
import { ref, computed } from 'vue'
|
||
// 组件名与模块 id 一致,供 <KeepAlive :include> 按 id 精确匹配
|
||
defineOptions({ name: 'cqy' })
|
||
import { useLocale } from '../../composables/useLocale.js'
|
||
|
||
const { t } = useLocale()
|
||
|
||
// 谷歌日历 embed URL(周视图)
|
||
const calendarSrc = computed(() =>
|
||
'https://calendar.google.com/calendar/embed?height=600&wkst=2&ctz=Australia%2FMelbourne&showPrint=0&mode=WEEK' +
|
||
'&src=Y2E0YTE5ZWYwNDM3OTYyYzY5YjEyYzYxYWVmOGVlZjY3MGU5ZDdmYjRlNzJlOTFjNDJjMzllM2Q2NGU5ZTAzNkBncm91cC5jYWxlbmRhci5nb29nbGUuY29t' +
|
||
'&src=emguYXVzdHJhbGlhbiNob2xpZGF5QGdyb3VwLnYuY2FsZW5kYXIuZ29vZ2xlLmNvbQ' +
|
||
'&color=%237986cb&color=%230b8043'
|
||
)
|
||
|
||
const loaded = ref(false)
|
||
</script>
|
||
|
||
<template>
|
||
<div class="calendar-page">
|
||
<div class="calendar-page__inner">
|
||
<h1 class="calendar-page__title">{{ t('tabs.calendar') }}</h1>
|
||
<div class="calendar-page__frame">
|
||
<!-- 加载占位骨架(覆盖层,iframe 加载完成后淡出) -->
|
||
<Transition name="fade">
|
||
<div v-if="!loaded" class="calendar-page__skeleton">
|
||
<div class="calendar-page__skeleton-text">{{ t('common.loading') }}</div>
|
||
</div>
|
||
</Transition>
|
||
<iframe
|
||
:src="calendarSrc"
|
||
class="calendar-page__iframe"
|
||
frameborder="0"
|
||
scrolling="no"
|
||
:title="t('tabs.calendar')"
|
||
@load="loaded = true"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.calendar-page {
|
||
padding: var(--space-2xl) 0;
|
||
}
|
||
/* 日历页用全宽容器(不受全局 .container 的 1080px 限制),仅留左右内边距 */
|
||
.calendar-page__inner {
|
||
width: 100%;
|
||
max-width: 100%;
|
||
margin: 0 auto;
|
||
padding: 0 var(--space-lg);
|
||
box-sizing: border-box;
|
||
}
|
||
.calendar-page__title {
|
||
font-size: 1.6rem;
|
||
margin-bottom: var(--space-lg);
|
||
}
|
||
.calendar-page__frame {
|
||
position: relative;
|
||
border-radius: var(--radius);
|
||
overflow: hidden;
|
||
box-shadow: var(--shadow);
|
||
border: 1px solid var(--border);
|
||
/* 自适应宽高:宽屏 16:9,窄屏更高 */
|
||
width: 100%;
|
||
aspect-ratio: 16 / 10;
|
||
min-height: 500px;
|
||
}
|
||
.calendar-page__iframe {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
border: 0;
|
||
}
|
||
.calendar-page__skeleton {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: var(--surface);
|
||
}
|
||
.calendar-page__skeleton-text {
|
||
color: var(--text-tertiary);
|
||
font-size: 0.95rem;
|
||
}
|
||
.fade-enter-active,
|
||
.fade-leave-active {
|
||
transition: opacity 0.4s ease;
|
||
}
|
||
.fade-enter-from,
|
||
.fade-leave-to {
|
||
opacity: 0;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.calendar-page__frame {
|
||
aspect-ratio: 4 / 3;
|
||
min-height: 400px;
|
||
}
|
||
}
|
||
</style>
|