- 全局重置(* / body)抽到 src/styles/global.css,仅独立 app 的 main.js 加载
- App.vue <style> 改 scoped,根及内部类名加 ttf- 前缀,避免与宿主冲突
- 根 class app -> ttf-app,min-height 改为填满容器以适配嵌入
- 加 defineOptions({ name: 'timetable' }) 供宿主 KeepAlive 匹配
- README 嵌入说明改为构建期组件集成 + git submodule
- 不影响独立运行:npm test 42 项通过,npm run build 通过
118 lines
3.3 KiB
Vue
118 lines
3.3 KiB
Vue
<script setup>
|
||
// 组件名与 mainPage 模块 id 一致,供 <KeepAlive :include> 按 id 精确匹配。
|
||
// 作为独立 app 运行时该名不影响行为。
|
||
defineOptions({ name: 'timetable' })
|
||
|
||
import { useCalendar } from './composables/useCalendar.js'
|
||
import DropZone from './components/DropZone.vue'
|
||
import HeaderBar from './components/HeaderBar.vue'
|
||
import EventList from './components/EventList.vue'
|
||
import EventDetail from './components/EventDetail.vue'
|
||
import MonthPreview from './components/MonthPreview.vue'
|
||
import WeekPreview from './components/WeekPreview.vue'
|
||
|
||
const { isLoaded, state, setViewMode } = useCalendar()
|
||
</script>
|
||
|
||
<template>
|
||
<div class="ttf-app">
|
||
<header class="ttf-header">
|
||
<div class="ttf-header-left">
|
||
<h1>ICS 日程整理器</h1>
|
||
<div v-if="isLoaded" class="ttf-view-switcher">
|
||
<button
|
||
:class="{ active: state.viewMode === 'edit' }"
|
||
@click="setViewMode('edit')"
|
||
>编辑</button>
|
||
<button
|
||
:class="{ active: state.viewMode === 'month' }"
|
||
@click="setViewMode('month')"
|
||
>月预览</button>
|
||
<button
|
||
:class="{ active: state.viewMode === 'week' }"
|
||
@click="setViewMode('week')"
|
||
>周预览</button>
|
||
</div>
|
||
</div>
|
||
<HeaderBar />
|
||
</header>
|
||
<main class="ttf-main">
|
||
<DropZone v-if="!isLoaded" />
|
||
<template v-else>
|
||
<EventList v-if="state.viewMode === 'edit'" />
|
||
<div class="ttf-detail-area">
|
||
<EventDetail v-if="state.viewMode === 'edit'" />
|
||
<MonthPreview v-else-if="state.viewMode === 'month'" />
|
||
<WeekPreview v-else-if="state.viewMode === 'week'" />
|
||
</div>
|
||
</template>
|
||
</main>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
/* scoped:样式仅作用于本组件,作为组件被嵌入时不污染宿主。
|
||
全局重置(* / body)已移至 src/styles/global.css,仅独立 app 加载。 */
|
||
.ttf-app {
|
||
display: flex;
|
||
flex-direction: column;
|
||
/* 适配嵌入:填满宿主 <main> 区域;独立 app 下 body 仍提供背景 */
|
||
min-height: 0;
|
||
height: 100%;
|
||
}
|
||
.ttf-header {
|
||
background: #2c3e50;
|
||
color: #fff;
|
||
padding: 14px 24px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
}
|
||
.ttf-header-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24px;
|
||
}
|
||
.ttf-header h1 { font-size: 18px; font-weight: 600; white-space: nowrap; }
|
||
.ttf-view-switcher {
|
||
display: flex;
|
||
background: #1a252f;
|
||
border-radius: 6px;
|
||
overflow: hidden;
|
||
}
|
||
.ttf-view-switcher button {
|
||
background: transparent;
|
||
color: #bdc3c7;
|
||
border: none;
|
||
padding: 6px 16px;
|
||
font-size: 13px;
|
||
cursor: pointer;
|
||
transition: all 0.15s;
|
||
}
|
||
.ttf-view-switcher button:hover { color: #fff; }
|
||
.ttf-view-switcher button.active {
|
||
background: #3498db;
|
||
color: #fff;
|
||
}
|
||
.ttf-main { flex: 1; display: flex; overflow: hidden; min-height: 0; }
|
||
.ttf-detail-area { flex: 1; overflow-y: auto; }
|
||
|
||
/* 移动端适配 */
|
||
@media (max-width: 768px) {
|
||
.ttf-header {
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
padding: 10px 12px;
|
||
}
|
||
.ttf-header-left {
|
||
width: 100%;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
}
|
||
.ttf-header h1 { font-size: 15px; }
|
||
.ttf-view-switcher button { padding: 5px 10px; font-size: 12px; }
|
||
.ttf-main { flex-direction: column; }
|
||
}
|
||
</style>
|