feat: 일정 주간/월간 뷰 전환 추가
상단 토글(주간/월간)로 보기 전환. 월간은 전통 달력 그리드(주×요일). - scheduleDate: firstOfMonth/addMonths/monthLabel/monthGridWeeks(+MonthDay) 추가 - schedule.store: viewMode + anchor 기반으로 주간/월간 범위·라벨·네비 일원화 (goPrev/goNext 가 모드별로 주/월 이동, setViewMode 시 범위 재조회) - ScheduleMonthGrid: 주 단위 다중일 막대(레인 패킹) + 초과 '+N', 카테고리 색·유형 필터·오늘/주말/이전·다음달 표기, 막대 클릭 시 상세 패널 - SchedulePage: SegmentedTabs 토글 + 주간/월간 조건부 렌더 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
// 일정 — 전사 공유 주간 타임라인(간트형) 캘린더
|
||||
// 일정 — 전사 공유 캘린더(주간 간트 / 월간 달력 그리드 전환)
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import AppShell from '@/layouts/AppShell.vue'
|
||||
import ScheduleTimeline from '@/components/schedule/ScheduleTimeline.vue'
|
||||
import ScheduleMonthGrid from '@/components/schedule/ScheduleMonthGrid.vue'
|
||||
import ScheduleDetailPanel from '@/components/schedule/ScheduleDetailPanel.vue'
|
||||
import ScheduleEventModal from '@/components/schedule/ScheduleEventModal.vue'
|
||||
import ScheduleCategoryModal from '@/components/schedule/ScheduleCategoryModal.vue'
|
||||
import ScheduleTypeFilter from '@/components/schedule/ScheduleTypeFilter.vue'
|
||||
import { useScheduleStore } from '@/stores/schedule.store'
|
||||
import SegmentedTabs from '@/components/common/SegmentedTabs.vue'
|
||||
import { useScheduleStore, type ScheduleViewMode } from '@/stores/schedule.store'
|
||||
import { useDialogStore } from '@/stores/dialog.store'
|
||||
import type {
|
||||
ApiScheduleEvent,
|
||||
@@ -18,6 +20,12 @@ import type {
|
||||
const store = useScheduleStore()
|
||||
const dialog = useDialogStore()
|
||||
|
||||
// 보기 모드 토글 옵션
|
||||
const VIEW_OPTIONS: { value: ScheduleViewMode; label: string }[] = [
|
||||
{ value: 'week', label: '주간' },
|
||||
{ value: 'month', label: '월간' },
|
||||
]
|
||||
|
||||
const selId = ref<string | null>(null)
|
||||
const eventModal = ref<{ init: ApiScheduleEvent | null } | null>(null)
|
||||
const catModal = ref<{ init: import('@/types/schedule').ApiScheduleCategory | null } | null>(null)
|
||||
@@ -107,8 +115,8 @@ async function onDeleteCategory(id: string): Promise<void> {
|
||||
<div class="navgroup">
|
||||
<button
|
||||
class="navbtn"
|
||||
title="이전 주"
|
||||
@click="store.goPrevWeek()"
|
||||
:title="store.viewMode === 'week' ? '이전 주' : '이전 달'"
|
||||
@click="store.goPrev()"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
@@ -121,8 +129,8 @@ async function onDeleteCategory(id: string): Promise<void> {
|
||||
</button>
|
||||
<button
|
||||
class="navbtn"
|
||||
title="다음 주"
|
||||
@click="store.goNextWeek()"
|
||||
:title="store.viewMode === 'week' ? '다음 주' : '다음 달'"
|
||||
@click="store.goNext()"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
@@ -136,6 +144,11 @@ async function onDeleteCategory(id: string): Promise<void> {
|
||||
</div>
|
||||
<span class="range">{{ store.rangeLabel }}</span>
|
||||
</div>
|
||||
<SegmentedTabs
|
||||
:model-value="store.viewMode"
|
||||
:options="VIEW_OPTIONS"
|
||||
@update:model-value="store.setViewMode"
|
||||
/>
|
||||
<div class="spacer" />
|
||||
<ScheduleTypeFilter
|
||||
:categories="store.categories"
|
||||
@@ -166,6 +179,7 @@ async function onDeleteCategory(id: string): Promise<void> {
|
||||
<div class="content-row">
|
||||
<div class="viewport">
|
||||
<ScheduleTimeline
|
||||
v-if="store.viewMode === 'week'"
|
||||
:categories="store.categories"
|
||||
:events="store.events"
|
||||
:days="store.days"
|
||||
@@ -174,6 +188,15 @@ async function onDeleteCategory(id: string): Promise<void> {
|
||||
@select="selId = $event"
|
||||
@add-category="openNewCategory"
|
||||
/>
|
||||
<ScheduleMonthGrid
|
||||
v-else
|
||||
:weeks="store.monthWeeks"
|
||||
:events="store.events"
|
||||
:categories="store.categories"
|
||||
:active-type-ids="store.activeTypeIds"
|
||||
:sel-id="selId"
|
||||
@select="selId = $event"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="selEvent"
|
||||
|
||||
Reference in New Issue
Block a user