fix
This commit is contained in:
@@ -2,7 +2,7 @@ import { flushPromises, mount } from '@vue/test-utils'
|
||||
import { computed } from 'vue'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import App from './App.vue'
|
||||
import { createEmptyBook } from './domain/teachingDesign'
|
||||
import { createEmptyBook } from '../shared/domain/teachingDesign'
|
||||
import * as booksApi from './services/booksApi'
|
||||
|
||||
vi.mock('./services/booksApi')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createEmptyTeachingDesign } from '../domain/teachingDesign'
|
||||
import { createEmptyTeachingDesign } from '../../shared/domain/teachingDesign'
|
||||
import A4Workspace from './A4Workspace.vue'
|
||||
|
||||
describe('A4Workspace', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { flushPromises, mount } from '@vue/test-utils'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createEmptyBook } from '../domain/teachingDesign'
|
||||
import { createEmptyBook } from '../../shared/domain/teachingDesign'
|
||||
import * as booksApi from '../services/booksApi'
|
||||
import BookListPage from './BookListPage.vue'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createEmptyTeachingDesign } from '../domain/teachingDesign'
|
||||
import { createEmptyTeachingDesign } from '../../shared/domain/teachingDesign'
|
||||
import LessonSidebar from './LessonSidebar.vue'
|
||||
|
||||
describe('LessonSidebar', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createEmptyTeachingDesign } from '../domain/teachingDesign'
|
||||
import { createEmptyTeachingDesign } from '../../shared/domain/teachingDesign'
|
||||
import PrintBook from './PrintBook.vue'
|
||||
|
||||
describe('PrintBook', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createEmptyTeachingDesign, type TeachingDesign } from '../domain/teachingDesign'
|
||||
import { createEmptyTeachingDesign, type TeachingDesign } from '../../shared/domain/teachingDesign'
|
||||
import TeachingDesignPage from './TeachingDesignPage.vue'
|
||||
|
||||
describe('TeachingDesignPage', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { flushPromises, mount } from '@vue/test-utils'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createEmptyBook, createEmptyTeachingDesign } from '../domain/teachingDesign'
|
||||
import { createEmptyBook, createEmptyTeachingDesign } from '../../shared/domain/teachingDesign'
|
||||
import * as booksApi from '../services/booksApi'
|
||||
import * as zipExporter from '../services/zipExporter'
|
||||
import BatchGenerateDialog from './BatchGenerateDialog.vue'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { flushPromises } from '@vue/test-utils'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createEmptyBook, createEmptyTeachingDesign, type TeachingBook } from '../domain/teachingDesign'
|
||||
import { createEmptyBook, createEmptyTeachingDesign, type TeachingBook } from '../../shared/domain/teachingDesign'
|
||||
import * as booksApi from '../services/booksApi'
|
||||
import { useTeachingBook } from './useTeachingBook'
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
type DesignId,
|
||||
type TeachingBook,
|
||||
type TeachingDesign,
|
||||
} from '../domain/teachingDesign'
|
||||
} from '../../shared/domain/teachingDesign'
|
||||
import * as booksApi from '../services/booksApi'
|
||||
import { parseTeachingDesign } from '../services/markdownParser'
|
||||
import { sortFilesNaturally } from '../services/naturalSort'
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import { describe, expect, expectTypeOf, it } from 'vitest'
|
||||
import {
|
||||
BOOK_SCHEMA_VERSION,
|
||||
createEmptyBook,
|
||||
createEmptyTeachingDesign,
|
||||
createTeachingStep,
|
||||
type DesignId,
|
||||
type TeachingBook,
|
||||
type TeachingDesign,
|
||||
} from './teachingDesign'
|
||||
|
||||
describe('createTeachingStep', () => {
|
||||
it('creates a named step with editable defaults and an ID', () => {
|
||||
const step = createTeachingStep(3)
|
||||
|
||||
expect(step.id).not.toBe('')
|
||||
expect(step).toMatchObject({
|
||||
name: '3. 教学环节',
|
||||
duration: '',
|
||||
content: '',
|
||||
teacherActivity: '',
|
||||
studentActivity: '',
|
||||
intention: '',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('createEmptyTeachingDesign', () => {
|
||||
it('creates editable defaults for missing lesson sections', () => {
|
||||
const design = createEmptyTeachingDesign('8.md')
|
||||
|
||||
expect(design.id).not.toBe('')
|
||||
expect(design.originalFilename).toBe('8.md')
|
||||
expect(design.processSteps).toHaveLength(1)
|
||||
expect(design.processSteps[0]?.id).not.toBe('')
|
||||
expect(design.boardDesign).toBe('')
|
||||
expect(design.warnings).toEqual([])
|
||||
})
|
||||
|
||||
it('creates independent nested state for each design', () => {
|
||||
const first = createEmptyTeachingDesign('1.md')
|
||||
const second = createEmptyTeachingDesign('2.md')
|
||||
|
||||
first.processSteps[0]!.name = 'Changed'
|
||||
first.warnings.push({ code: 'missing-title', message: 'Missing title' })
|
||||
|
||||
expect(first.id).not.toBe(second.id)
|
||||
expect(first.processSteps).not.toBe(second.processSteps)
|
||||
expect(first.processSteps[0]).not.toBe(second.processSteps[0])
|
||||
expect(second.processSteps[0]?.name).toBe('1. 教学环节')
|
||||
expect(second.warnings).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('createEmptyBook', () => {
|
||||
it('creates the schema defaults with no selected page and an ISO timestamp', () => {
|
||||
const book = createEmptyBook()
|
||||
|
||||
expect(book.schemaVersion).toBe(BOOK_SCHEMA_VERSION)
|
||||
expect(book.selectedId).toBeNull()
|
||||
expect(book).not.toHaveProperty('cover')
|
||||
expect(new Date(book.updatedAt).toISOString()).toBe(book.updatedAt)
|
||||
})
|
||||
|
||||
it('creates independent design collections', () => {
|
||||
const first = createEmptyBook()
|
||||
const second = createEmptyBook()
|
||||
|
||||
first.designs.push(createEmptyTeachingDesign('1.md'))
|
||||
|
||||
expect(first.designs).not.toBe(second.designs)
|
||||
expect(second.designs).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('domain types', () => {
|
||||
it('uses branded string design IDs and literal schema versions', () => {
|
||||
expectTypeOf<DesignId>().toExtend<string>()
|
||||
expectTypeOf<TeachingDesign['id']>().toEqualTypeOf<DesignId>()
|
||||
expectTypeOf<TeachingBook['selectedId']>().toEqualTypeOf<DesignId | null>()
|
||||
expectTypeOf<TeachingBook['schemaVersion']>().toEqualTypeOf<
|
||||
typeof BOOK_SCHEMA_VERSION
|
||||
>()
|
||||
})
|
||||
})
|
||||
@@ -1,105 +0,0 @@
|
||||
export const BOOK_SCHEMA_VERSION = 1
|
||||
|
||||
declare const designIdBrand: unique symbol
|
||||
|
||||
export type DesignId = string & {
|
||||
readonly [designIdBrand]: true
|
||||
}
|
||||
|
||||
export type ParseWarningCode =
|
||||
| 'missing-title'
|
||||
| 'missing-basic-field'
|
||||
| 'missing-process'
|
||||
| 'invalid-process-table'
|
||||
| 'missing-board'
|
||||
| 'missing-reflection'
|
||||
| 'unclassified-content'
|
||||
|
||||
export interface ParseWarning {
|
||||
code: ParseWarningCode
|
||||
message: string
|
||||
}
|
||||
|
||||
export interface TeachingStep {
|
||||
id: string
|
||||
name: string
|
||||
duration: string
|
||||
content: string
|
||||
teacherActivity: string
|
||||
studentActivity: string
|
||||
intention: string
|
||||
}
|
||||
|
||||
export interface TeachingDesign {
|
||||
id: DesignId
|
||||
originalFilename: string
|
||||
title: string
|
||||
topic: string
|
||||
duration: string
|
||||
knowledgeObjective: string
|
||||
skillObjective: string
|
||||
literacyObjective: string
|
||||
keyPoint: string
|
||||
difficultPoint: string
|
||||
resources: string
|
||||
processSteps: TeachingStep[]
|
||||
boardDesign: string
|
||||
effectiveness: string
|
||||
reflection: string
|
||||
additionalContent: string
|
||||
warnings: ParseWarning[]
|
||||
}
|
||||
|
||||
export interface TeachingBook {
|
||||
schemaVersion: typeof BOOK_SCHEMA_VERSION
|
||||
designs: TeachingDesign[]
|
||||
selectedId: DesignId | null
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
function createDesignId(): DesignId {
|
||||
return crypto.randomUUID() as DesignId
|
||||
}
|
||||
|
||||
export function createTeachingStep(index = 1): TeachingStep {
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
name: `${index}. 教学环节`,
|
||||
duration: '',
|
||||
content: '',
|
||||
teacherActivity: '',
|
||||
studentActivity: '',
|
||||
intention: '',
|
||||
}
|
||||
}
|
||||
|
||||
export function createEmptyTeachingDesign(filename: string): TeachingDesign {
|
||||
return {
|
||||
id: createDesignId(),
|
||||
originalFilename: filename,
|
||||
title: '',
|
||||
topic: '',
|
||||
duration: '',
|
||||
knowledgeObjective: '',
|
||||
skillObjective: '',
|
||||
literacyObjective: '',
|
||||
keyPoint: '',
|
||||
difficultPoint: '',
|
||||
resources: '',
|
||||
processSteps: [createTeachingStep()],
|
||||
boardDesign: '',
|
||||
effectiveness: '',
|
||||
reflection: '',
|
||||
additionalContent: '',
|
||||
warnings: [],
|
||||
}
|
||||
}
|
||||
|
||||
export function createEmptyBook(): TeachingBook {
|
||||
return {
|
||||
schemaVersion: BOOK_SCHEMA_VERSION,
|
||||
designs: [],
|
||||
selectedId: null,
|
||||
updatedAt: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createEmptyBook } from '../domain/teachingDesign'
|
||||
import { createEmptyBook } from '../../shared/domain/teachingDesign'
|
||||
import * as booksApi from './booksApi'
|
||||
|
||||
describe('booksApi', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { TeachingBook } from '../domain/teachingDesign'
|
||||
import type { TeachingBook } from '../../shared/domain/teachingDesign'
|
||||
import { authedFetch } from '../composables/useAuth'
|
||||
|
||||
export interface BookSummary {
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
type ParseWarning,
|
||||
type TeachingDesign,
|
||||
type TeachingStep,
|
||||
} from '../domain/teachingDesign'
|
||||
} from '../../shared/domain/teachingDesign'
|
||||
import { extractMarkdownTable } from './markdownTable'
|
||||
|
||||
const BR = /<br\s*\/?>/gi
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { TeachingDesign } from '../domain/teachingDesign'
|
||||
import type { TeachingDesign } from '../../shared/domain/teachingDesign'
|
||||
|
||||
function escapeCell(value: string): string {
|
||||
return value
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import JSZip from 'jszip'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createEmptyTeachingDesign } from '../domain/teachingDesign'
|
||||
import { createEmptyTeachingDesign } from '../../shared/domain/teachingDesign'
|
||||
import { createBookZip } from './zipExporter'
|
||||
|
||||
describe('createBookZip', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import JSZip from 'jszip'
|
||||
import type { TeachingDesign } from '../domain/teachingDesign'
|
||||
import type { TeachingDesign } from '../../shared/domain/teachingDesign'
|
||||
import { writeTeachingDesignMarkdown } from './markdownWriter'
|
||||
|
||||
export async function createBookZip(designs: readonly TeachingDesign[]): Promise<Blob> {
|
||||
|
||||
Reference in New Issue
Block a user