Files

496 lines
17 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from typing import Optional, List, Any, Dict
from pydantic import BaseModel, ConfigDict, Field
from app.base_schema import CSTDatetime
# ==================== SmartTable ====================
class SmartTableCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=200, description="表名")
icon: str = Field(default="Grid", max_length=50, description="图标")
description: Optional[str] = Field(None, description="描述")
type: str = Field(default="table", description="类型: table / document")
content: Optional[Dict[str, Any]] = Field(None, description="文档内容(Tiptap JSON), 仅 type=document 时使用")
parent_id: Optional[str] = Field(None, description="父页面ID")
wiki_space_id: Optional[str] = Field(None, description="所属文档库ID")
class SmartTableUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=200, description="表名")
icon: Optional[str] = Field(None, max_length=50, description="图标")
description: Optional[str] = Field(None, description="描述")
active_view_id: Optional[str] = Field(None, description="当前激活视图ID")
content: Optional[Dict[str, Any]] = Field(None, description="文档内容(Tiptap JSON)")
parent_id: Optional[str] = Field(None, description="父页面ID")
class SmartTableMove(BaseModel):
parent_id: Optional[str] = Field(None, description="目标父页面IDnull 表示移到根级")
after_id: Optional[str] = Field(None, description="排在此项之后,null 表示排在同级首位")
class SmartTableResponse(BaseModel):
id: str
name: str
icon: str = "Grid"
description: Optional[str] = None
active_view_id: Optional[str] = None
type: str = "table"
parent_id: Optional[str] = None
wiki_space_id: Optional[str] = None
sort: int = 0
sys_create_datetime: Optional[CSTDatetime] = None
sys_update_datetime: Optional[CSTDatetime] = None
model_config = ConfigDict(from_attributes=True)
class SmartTableSimple(BaseModel):
"""列表简要信息(含 parent_id 以便前端构建树)"""
id: str
name: str
icon: str = "Grid"
type: str = "table"
parent_id: Optional[str] = None
wiki_space_id: Optional[str] = None
sort: int = 0
model_config = ConfigDict(from_attributes=True)
# ==================== SmartField ====================
class SmartFieldCreate(BaseModel):
table_id: Optional[str] = Field(None, description="所属表ID(从URL路径注入)")
name: str = Field(..., min_length=1, max_length=200, description="字段名")
type: str = Field(..., description="字段类型")
width: int = Field(default=150, description="列宽")
visible: bool = Field(default=True, description="是否可见")
required: bool = Field(default=False, description="是否必填")
description: Optional[str] = Field(None, description="描述")
config: Optional[Dict[str, Any]] = Field(default_factory=dict, description="扩展配置")
sort: int = Field(default=0, description="排序")
class SmartFieldUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=200, description="字段名")
type: Optional[str] = Field(None, description="字段类型")
width: Optional[int] = Field(None, description="列宽")
visible: Optional[bool] = Field(None, description="是否可见")
required: Optional[bool] = Field(None, description="是否必填")
description: Optional[str] = Field(None, description="描述")
config: Optional[Dict[str, Any]] = Field(None, description="扩展配置")
sort: Optional[int] = Field(None, description="排序")
class SmartFieldResponse(BaseModel):
id: str
table_id: str
name: str
type: str
width: int = 150
visible: bool = True
required: bool = False
description: Optional[str] = None
config: Optional[Dict[str, Any]] = None
sort: int = 0
sys_create_datetime: Optional[CSTDatetime] = None
sys_update_datetime: Optional[CSTDatetime] = None
model_config = ConfigDict(from_attributes=True)
class SmartFieldReorder(BaseModel):
field_ids: List[str] = Field(..., description="按顺序排列的字段ID列表")
# ==================== SmartRecord ====================
class SmartRecordCreate(BaseModel):
table_id: Optional[str] = Field(None, description="所属表ID(从URL路径注入)")
values: Dict[str, Any] = Field(default_factory=dict, description="字段值映射")
class SmartRecordUpdate(BaseModel):
values: Optional[Dict[str, Any]] = Field(None, description="字段值映射")
class SmartRecordCellUpdate(BaseModel):
"""更新单个单元格"""
field_id: str = Field(..., description="字段ID")
value: Any = Field(None, description="单元格值")
class SmartRecordResponse(BaseModel):
id: str
table_id: str
values: Dict[str, Any] = {}
sys_create_datetime: Optional[CSTDatetime] = None
sys_update_datetime: Optional[CSTDatetime] = None
sys_creator_id: Optional[str] = None
sys_modifier_id: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
class SmartRecordBatchDelete(BaseModel):
ids: List[str] = Field(..., description="要删除的记录ID列表")
class SmartRecordBatchRestore(BaseModel):
ids: List[str] = Field(..., description="要恢复的记录ID列表")
class TrashRecordResponse(BaseModel):
id: str
table_id: str
values: Dict[str, Any] = {}
sys_create_datetime: Optional[CSTDatetime] = None
sys_update_datetime: Optional[CSTDatetime] = None
sys_creator_id: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
class TrashListResponse(BaseModel):
items: List[TrashRecordResponse]
total: int
# ==================== SmartView ====================
class SmartViewCreate(BaseModel):
table_id: Optional[str] = Field(None, description="所属表ID(从URL路径注入)")
name: str = Field(..., min_length=1, max_length=200, description="视图名")
type: str = Field(default="grid", description="视图类型")
config: Optional[Dict[str, Any]] = Field(default_factory=dict, description="视图配置")
sort: int = Field(default=0, description="排序")
class SmartViewUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=200, description="视图名")
type: Optional[str] = Field(None, description="视图类型")
config: Optional[Dict[str, Any]] = Field(None, description="视图配置")
sort: Optional[int] = Field(None, description="排序")
class SmartViewResponse(BaseModel):
id: str
table_id: str
name: str
type: str = "grid"
config: Optional[Dict[str, Any]] = None
sort: int = 0
sys_create_datetime: Optional[CSTDatetime] = None
sys_update_datetime: Optional[CSTDatetime] = None
model_config = ConfigDict(from_attributes=True)
# ==================== Record Query (Server-side filter/sort/search) ====================
class RecordFilterRule(BaseModel):
field_id: str = Field(..., description="字段ID")
operator: str = Field(..., description="操作符: equals, notEquals, contains, notContains, isEmpty, isNotEmpty, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual")
value: Any = Field(None, description="筛选值")
class RecordSortRule(BaseModel):
field_id: str = Field(..., description="字段ID")
direction: str = Field(default="asc", description="排序方向: asc / desc")
class RecordQuery(BaseModel):
filters: List[RecordFilterRule] = Field(default_factory=list, description="筛选条件")
filter_logic: str = Field(default="and", description="筛选逻辑: and / or")
sorts: List[RecordSortRule] = Field(default_factory=list, description="排序规则")
search: Optional[str] = Field(None, description="全文搜索关键词")
search_field_ids: Optional[List[str]] = Field(None, description="搜索范围字段ID列表,为空搜索所有文本字段")
group_field_id: Optional[str] = Field(None, description="分组字段ID")
cursor: Optional[str] = Field(None, description="游标(上一页最后一条记录的ID")
limit: int = Field(default=200, ge=1, le=5000, description="每页数量")
class RecordGroupItem(BaseModel):
key: str
label: str
records: List[SmartRecordResponse] = []
class GroupedRecordsResponse(BaseModel):
groups: List[RecordGroupItem]
total: int
class SmartRecordReorder(BaseModel):
record_ids: List[str] = Field(..., description="按顺序排列的记录ID列表")
# ==================== Batch Cell Update ====================
class SmartRecordBatchCellUpdate(BaseModel):
"""批量更新多个单元格"""
cells: Dict[str, Any] = Field(..., description="fieldId->value 映射")
class MultiRecordCellUpdate(BaseModel):
"""单条记录的更新项"""
record_id: str = Field(..., description="记录ID")
cells: Dict[str, Any] = Field(..., description="fieldId->value 映射")
class MultiRecordBatchUpdate(BaseModel):
"""批量更新多条记录的单元格 - 合并为单次事务"""
updates: List[MultiRecordCellUpdate] = Field(..., description="更新列表", max_length=200)
# ==================== Cursor Pagination ====================
class CursorPaginatedRecords(BaseModel):
items: List[SmartRecordResponse]
total: int
next_cursor: Optional[str] = None
has_more: bool = False
# ==================== Full Table Load ====================
# ==================== Link / Lookup / Rollup ====================
class LinkCellUpdate(BaseModel):
"""更新 Link 字段的关联记录"""
record_ids: List[str] = Field(..., description="目标记录ID列表")
class LinkedRecordItem(BaseModel):
"""关联记录摘要"""
id: str
title: str = ""
class RecordSearchResult(BaseModel):
"""搜索目标表记录结果"""
id: str
title: str = ""
class RecordSearchQuery(BaseModel):
"""搜索请求"""
keyword: str = Field(default="", description="搜索关键词")
limit: int = Field(default=20, ge=1, le=100, description="返回数量")
# ==================== Full Table Load ====================
class SmartTableFull(BaseModel):
"""完整表数据(含字段、首页记录、视图)"""
id: str
name: str
icon: str = "Grid"
description: Optional[str] = None
active_view_id: Optional[str] = None
type: str = "table"
parent_id: Optional[str] = None
wiki_space_id: Optional[str] = None
content: Optional[Dict[str, Any]] = None
fields: List[SmartFieldResponse] = []
records: List[SmartRecordResponse] = []
views: List[SmartViewResponse] = []
record_total: int = 0
next_cursor: Optional[str] = None
has_more: bool = False
sys_create_datetime: Optional[CSTDatetime] = None
sys_update_datetime: Optional[CSTDatetime] = None
sys_creator_id: Optional[str] = None
creator_name: Optional[str] = None
creator_avatar: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
# ==================== Comment ====================
class CommentCreate(BaseModel):
content: str = Field(..., min_length=1, max_length=5000, description="评论内容")
mentions: List[str] = Field(default_factory=list, description="被@提及的用户ID列表")
parent_id: Optional[str] = Field(None, description="父评论ID(回复)")
class CommentUpdate(BaseModel):
content: str = Field(..., min_length=1, max_length=5000, description="评论内容")
mentions: List[str] = Field(default_factory=list, description="被@提及的用户ID列表")
class CommentResponse(BaseModel):
id: str
record_id: str
user_id: str
content: str
mentions: List[str] = []
parent_id: Optional[str] = None
sys_create_datetime: Optional[CSTDatetime] = None
sys_update_datetime: Optional[CSTDatetime] = None
user_name: Optional[str] = None
user_avatar: Optional[str] = None
replies: List["CommentResponse"] = []
model_config = ConfigDict(from_attributes=True)
CommentResponse.model_rebuild()
# ==================== Summary / Aggregation ====================
class SummaryRequest(BaseModel):
"""汇总请求:指定字段及聚合方式"""
aggregations: Dict[str, str] = Field(
..., description="fieldId -> aggregation_type 映射,如 {'fld_abc': 'SUM'}"
)
filters: List[RecordFilterRule] = Field(default_factory=list, description="筛选条件")
filter_logic: str = Field(default="and", description="筛选逻辑: and / or")
search: Optional[str] = Field(None, description="搜索关键词")
class SummaryResponse(BaseModel):
"""汇总响应"""
summaries: Dict[str, Any] = Field(
default_factory=dict,
description="fieldId -> 聚合结果,如 {'fld_abc': 12345.67}"
)
total_count: int = 0
# ==================== Document ====================
class DocumentContentUpdate(BaseModel):
"""更新文档内容"""
content: Dict[str, Any] = Field(..., description="Tiptap JSON 文档内容")
# ==================== Document Version ====================
class DocumentVersionCreate(BaseModel):
"""手动创建版本"""
change_summary: Optional[str] = Field(None, max_length=500, description="变更摘要")
class DocumentVersionResponse(BaseModel):
id: str
document_id: str
version: int
title: Optional[str] = None
change_summary: Optional[str] = None
content_size: int = 0
sys_create_datetime: Optional[CSTDatetime] = None
sys_creator_id: Optional[str] = None
creator_name: Optional[str] = None
creator_avatar: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
class DocumentVersionDetail(DocumentVersionResponse):
"""版本详情(含完整内容)"""
content: Dict[str, Any] = {}
class DocumentVersionCompare(BaseModel):
"""版本对比结果"""
version_from: DocumentVersionDetail
version_to: DocumentVersionDetail
# ==================== Document Template ====================
class DocumentTemplateCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=200, description="模板名称")
description: Optional[str] = Field(None, description="模板描述")
icon: str = Field(default="FileText", max_length=50, description="模板图标")
category: str = Field(default="custom", max_length=50, description="分类")
content: Dict[str, Any] = Field(..., description="模板内容(Tiptap JSON)")
preview_image: Optional[str] = Field(None, description="预览图URL")
class DocumentTemplateUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=200, description="模板名称")
description: Optional[str] = Field(None, description="模板描述")
icon: Optional[str] = Field(None, max_length=50, description="模板图标")
category: Optional[str] = Field(None, max_length=50, description="分类")
content: Optional[Dict[str, Any]] = Field(None, description="模板内容(Tiptap JSON)")
preview_image: Optional[str] = Field(None, description="预览图URL")
class DocumentTemplateResponse(BaseModel):
id: str
name: str
description: Optional[str] = None
icon: str = "FileText"
category: str = "custom"
preview_image: Optional[str] = None
is_system: bool = False
use_count: int = 0
sys_create_datetime: Optional[CSTDatetime] = None
sys_update_datetime: Optional[CSTDatetime] = None
sys_creator_id: Optional[str] = None
creator_name: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
class DocumentTemplateDetail(DocumentTemplateResponse):
"""模板详情(含完整内容)"""
content: Dict[str, Any] = {}
# ==================== Wiki Space ====================
class WikiSpaceCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=200, description="文档库名称")
icon: str = Field(default="BookOpen", max_length=50, description="图标")
avatar: Optional[str] = Field(None, description="头像文件ID")
description: Optional[str] = Field(None, description="描述")
cover: Optional[str] = Field(None, description="封面图URL")
category: str = Field(default="default", max_length=50, description="分类标签")
visibility: str = Field(default="private", description="可见性: private/team/public")
class WikiSpaceUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=200, description="文档库名称")
icon: Optional[str] = Field(None, max_length=50, description="图标")
avatar: Optional[str] = Field(None, description="头像文件ID")
description: Optional[str] = Field(None, description="描述")
cover: Optional[str] = Field(None, description="封面图URL")
category: Optional[str] = Field(None, max_length=50, description="分类标签")
visibility: Optional[str] = Field(None, description="可见性: private/team/public")
class WikiSpaceResponse(BaseModel):
id: str
name: str
icon: str = "BookOpen"
avatar: Optional[str] = None
description: Optional[str] = None
cover: Optional[str] = None
category: str = "default"
visibility: str = "private"
sort: int = 0
sys_create_datetime: Optional[CSTDatetime] = None
sys_update_datetime: Optional[CSTDatetime] = None
sys_creator_id: Optional[str] = None
creator_name: Optional[str] = None
model_config = ConfigDict(from_attributes=True)
class WikiSpaceListItem(WikiSpaceResponse):
"""列表项,含文档数量"""
document_count: int = 0
class WikiSpaceDetail(WikiSpaceResponse):
"""详情,含文档列表"""
documents: List[SmartTableSimple] = []