496 lines
17 KiB
Python
496 lines
17 KiB
Python
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="目标父页面ID,null 表示移到根级")
|
||
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] = []
|