90ca061db8
1、为文档增加编辑接口和前端编辑抽屉,文档列表与详情页统一按创建、更新、删除权限展示操作。 2、将文档版本上传和分发改为抽屉交互,并在详情页补充版本删除权限检查。 3、增强全局面包屑上下文和详情页标题同步,避免详情页重复或缺失导航信息。 4、按项目权限过滤快捷入口、首页费用指标和 eTMF 新建入口,并补充对应前端测试。
173 lines
5.9 KiB
Python
173 lines
5.9 KiB
Python
import uuid
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, File, Form, Query, UploadFile, status
|
|
from fastapi.responses import FileResponse
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.deps import get_current_user, get_db_session
|
|
from app.schemas.acknowledgement import AcknowledgementCreate, AcknowledgementRead
|
|
from app.schemas.common import PaginatedResponse
|
|
from app.schemas.distribution import DistributionCreate, DistributionRead
|
|
from app.schemas.document import DocumentCreate, DocumentDetail, DocumentSummary, DocumentUpdate
|
|
from app.schemas.document_version import DocumentVersionRead
|
|
from app.services import document_service
|
|
from app.utils.pagination import paginate
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post(
|
|
"/documents",
|
|
response_model=DocumentSummary,
|
|
status_code=status.HTTP_201_CREATED,
|
|
)
|
|
async def create_document(
|
|
payload: DocumentCreate,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> DocumentSummary:
|
|
doc = await document_service.create_document(db, payload, current_user)
|
|
return DocumentSummary.model_validate(doc)
|
|
|
|
|
|
@router.get("/documents", response_model=PaginatedResponse[DocumentSummary])
|
|
async def list_documents(
|
|
trial_id: uuid.UUID = Query(...),
|
|
site_id: Optional[uuid.UUID] = Query(None),
|
|
doc_type: Optional[str] = Query(None),
|
|
scope_type: Optional[str] = Query(None),
|
|
status_value: Optional[str] = Query(None, alias="status"),
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> PaginatedResponse[DocumentSummary]:
|
|
items = await document_service.list_documents(
|
|
db,
|
|
trial_id=trial_id,
|
|
site_id=site_id,
|
|
doc_type=doc_type,
|
|
status=status_value,
|
|
scope_type=scope_type,
|
|
skip=skip,
|
|
limit=limit,
|
|
current_user=current_user,
|
|
)
|
|
return paginate(items, total=len(items))
|
|
|
|
|
|
@router.get("/documents/{document_id}", response_model=DocumentDetail)
|
|
async def get_document_detail(
|
|
document_id: uuid.UUID,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> DocumentDetail:
|
|
return await document_service.get_document_detail(db, document_id, current_user)
|
|
|
|
|
|
@router.patch("/documents/{document_id}", response_model=DocumentSummary)
|
|
async def update_document(
|
|
document_id: uuid.UUID,
|
|
payload: DocumentUpdate,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> DocumentSummary:
|
|
doc = await document_service.update_document(db, document_id, payload, current_user)
|
|
return DocumentSummary.model_validate(doc)
|
|
|
|
|
|
@router.delete("/documents/{document_id}", response_model=DocumentSummary)
|
|
async def delete_document(
|
|
document_id: uuid.UUID,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> DocumentSummary:
|
|
doc = await document_service.delete_document(db, document_id, current_user)
|
|
return DocumentSummary.model_validate(doc)
|
|
|
|
|
|
@router.post(
|
|
"/documents/{document_id}/versions",
|
|
response_model=DocumentVersionRead,
|
|
status_code=status.HTTP_201_CREATED,
|
|
)
|
|
async def create_version(
|
|
document_id: uuid.UUID,
|
|
version_no: str = Form(...),
|
|
version_date: str = Form(...),
|
|
change_summary: Optional[str] = Form(None),
|
|
parent_version_id: Optional[uuid.UUID] = Form(None),
|
|
file: UploadFile = File(...),
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> DocumentVersionRead:
|
|
version = await document_service.create_version(
|
|
db,
|
|
document_id,
|
|
version_no=version_no,
|
|
version_date=version_date,
|
|
change_summary=change_summary,
|
|
parent_version_id=parent_version_id,
|
|
file=file,
|
|
current_user=current_user,
|
|
)
|
|
return DocumentVersionRead.model_validate(version)
|
|
|
|
|
|
@router.get("/versions/{version_id}/download", response_class=FileResponse)
|
|
async def download_version(
|
|
version_id: uuid.UUID,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
):
|
|
return await document_service.get_version_download_response(db, version_id, current_user)
|
|
|
|
|
|
@router.delete("/versions/{version_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
async def delete_version(
|
|
version_id: uuid.UUID,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> None:
|
|
await document_service.delete_version(db, version_id, current_user)
|
|
|
|
|
|
@router.post(
|
|
"/versions/{version_id}/distributions",
|
|
response_model=list[DistributionRead],
|
|
status_code=status.HTTP_201_CREATED,
|
|
)
|
|
async def create_distributions(
|
|
version_id: uuid.UUID,
|
|
payload: DistributionCreate,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> list[DistributionRead]:
|
|
distributions = await document_service.create_distributions(db, version_id, payload, current_user)
|
|
return [DistributionRead.model_validate(d) for d in distributions]
|
|
|
|
|
|
@router.get("/versions/{version_id}/distributions", response_model=list[DistributionRead])
|
|
async def list_distributions(
|
|
version_id: uuid.UUID,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> list[DistributionRead]:
|
|
return await document_service.list_distributions(db, version_id, current_user)
|
|
|
|
|
|
@router.post(
|
|
"/distributions/{distribution_id}/acknowledgements",
|
|
response_model=AcknowledgementRead,
|
|
status_code=status.HTTP_201_CREATED,
|
|
)
|
|
async def create_acknowledgement(
|
|
distribution_id: uuid.UUID,
|
|
payload: AcknowledgementCreate,
|
|
db: AsyncSession = Depends(get_db_session),
|
|
current_user=Depends(get_current_user),
|
|
) -> AcknowledgementRead:
|
|
ack = await document_service.create_acknowledgement(db, distribution_id, payload, current_user)
|
|
return AcknowledgementRead.model_validate(ack)
|