feat: add login gate and admin navigation to App.vue

This commit is contained in:
2026-06-16 00:28:06 -06:00
parent 2503bf83fd
commit f76ff17530
3 changed files with 45 additions and 5 deletions

View File

@@ -1,10 +1,18 @@
import { flushPromises, mount } from '@vue/test-utils' import { flushPromises, mount } from '@vue/test-utils'
import { computed, ref } from 'vue'
import { beforeEach, describe, expect, it, vi } from 'vitest' import { beforeEach, describe, expect, it, vi } from 'vitest'
import App from './App.vue' import App from './App.vue'
import { createEmptyBook } from './domain/teachingDesign' import { createEmptyBook } from './domain/teachingDesign'
import * as booksApi from './services/booksApi' import * as booksApi from './services/booksApi'
vi.mock('./services/booksApi') vi.mock('./services/booksApi')
vi.mock('./composables/useAuth', () => ({
useAuth: () => ({
isLoggedIn: computed(() => true),
fetchMe: vi.fn(),
user: ref(null),
}),
}))
describe('App', () => { describe('App', () => {
beforeEach(() => { beforeEach(() => {
@@ -17,7 +25,7 @@ describe('App', () => {
const wrapper = mount(App) const wrapper = mount(App)
await flushPromises() await flushPromises()
expect(wrapper.text()).toContain('教学设计整本') expect(wrapper.text()).toContain('教学设计')
expect(wrapper.text()).toContain('新建整本') expect(wrapper.text()).toContain('新建整本')
}) })
@@ -61,6 +69,6 @@ describe('App', () => {
await wrapper.get('[data-testid="back"]').trigger('click') await wrapper.get('[data-testid="back"]').trigger('click')
await flushPromises() await flushPromises()
expect(wrapper.text()).toContain('教学设计整本') expect(wrapper.text()).toContain('教学设计')
}) })
}) })

View File

@@ -1,20 +1,48 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { onMounted, ref } from 'vue'
import AdminPage from './components/AdminPage.vue'
import BookListPage from './components/BookListPage.vue' import BookListPage from './components/BookListPage.vue'
import LoginPage from './components/LoginPage.vue'
import WorkspaceView from './components/WorkspaceView.vue' import WorkspaceView from './components/WorkspaceView.vue'
import { useAuth } from './composables/useAuth'
const { isLoggedIn, fetchMe } = useAuth()
const currentBookId = ref<string | null>(null) const currentBookId = ref<string | null>(null)
const showAdmin = ref(false)
onMounted(async () => {
await fetchMe()
})
function openBook(id: string): void { function openBook(id: string): void {
currentBookId.value = id currentBookId.value = id
showAdmin.value = false
} }
function backToList(): void { function backToList(): void {
currentBookId.value = null currentBookId.value = null
} }
function openAdmin(): void {
showAdmin.value = true
currentBookId.value = null
}
function closeAdmin(): void {
showAdmin.value = false
}
</script> </script>
<template> <template>
<BookListPage v-if="!currentBookId" @open="openBook" /> <LoginPage v-if="!isLoggedIn" @success="fetchMe" />
<WorkspaceView v-else :key="currentBookId" :book-id="currentBookId" @back="backToList" /> <template v-else>
<AdminPage v-if="showAdmin" @back="closeAdmin" />
<WorkspaceView
v-else-if="currentBookId"
:key="currentBookId"
:book-id="currentBookId"
@back="backToList"
/>
<BookListPage v-else @open="openBook" @admin="openAdmin" />
</template>
</template> </template>

View File

@@ -0,0 +1,4 @@
<script setup lang="ts">
defineEmits<{ back: [] }>()
</script>
<template><div>Admin placeholder</div></template>