483fdb982b
- 创建后端数据库模型:DocumentChapter 和 Document,支持按章节组织的树形文档结构 - 创建数据库迁移文件:002_add_document_management.sql - 创建 Pydantic schemas:定义文档和章节的请求/响应模型 - 创建后端服务层:document_service.py 实现 CRUD 和树形结构构建 - 创建 API 路由:/api/v1/documents 和 /api/v1/documents/chapters,支持完整的 RESTful 操作 - 创建前端类型定义:document.ts - 创建文档管理页面:/admin/documents,包含章节树形目录和文档表格,支持增删改查 - 创建文档展示页面:/admin/docs-view,左侧目录树右侧内容展示,支持 Markdown 渲染 - 安装 react-markdown 依赖用于文档内容展示 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai>
77 lines
2.5 KiB
Python
77 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
from sqlalchemy import ForeignKey, Integer, String, Text, DateTime
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
from sqlalchemy.sql import func
|
|
|
|
from ..core.database import Base
|
|
|
|
if TYPE_CHECKING:
|
|
pass
|
|
|
|
|
|
class DocumentChapter(Base):
|
|
__tablename__ = "document_chapters"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
|
name: Mapped[str] = mapped_column(String(128), index=True)
|
|
description: Mapped[str | None] = mapped_column(String(512))
|
|
parent_id: Mapped[int | None] = mapped_column(
|
|
ForeignKey("document_chapters.id", ondelete="CASCADE"),
|
|
index=True,
|
|
)
|
|
sort_order: Mapped[int] = mapped_column(Integer, default=0, index=True)
|
|
created_at: Mapped[DateTime] = mapped_column(DateTime, server_default=func.now())
|
|
updated_at: Mapped[DateTime] = mapped_column(
|
|
DateTime, server_default=func.now(), onupdate=func.now()
|
|
)
|
|
|
|
parent: Mapped[DocumentChapter | None] = relationship(
|
|
"DocumentChapter",
|
|
remote_side=lambda: [DocumentChapter.id],
|
|
back_populates="children",
|
|
lazy="selectin",
|
|
)
|
|
children: Mapped[list[DocumentChapter]] = relationship(
|
|
"DocumentChapter",
|
|
back_populates="parent",
|
|
lazy="selectin",
|
|
order_by="DocumentChapter.sort_order",
|
|
cascade="all, delete-orphan",
|
|
)
|
|
documents: Mapped[list[Document]] = relationship(
|
|
"Document",
|
|
back_populates="chapter",
|
|
lazy="selectin",
|
|
order_by="Document.sort_order",
|
|
cascade="all, delete-orphan",
|
|
)
|
|
|
|
|
|
class Document(Base):
|
|
__tablename__ = "documents"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
|
title: Mapped[str] = mapped_column(String(256), index=True)
|
|
content: Mapped[str] = mapped_column(Text)
|
|
chapter_id: Mapped[int | None] = mapped_column(
|
|
ForeignKey("document_chapters.id", ondelete="CASCADE"),
|
|
index=True,
|
|
)
|
|
sort_order: Mapped[int] = mapped_column(Integer, default=0, index=True)
|
|
status: Mapped[str] = mapped_column(
|
|
String(16), default="draft", index=True
|
|
)
|
|
created_at: Mapped[DateTime] = mapped_column(DateTime, server_default=func.now())
|
|
updated_at: Mapped[DateTime] = mapped_column(
|
|
DateTime, server_default=func.now(), onupdate=func.now()
|
|
)
|
|
|
|
chapter: Mapped[DocumentChapter | None] = relationship(
|
|
"DocumentChapter",
|
|
back_populates="documents",
|
|
lazy="selectin",
|
|
)
|