from django.contrib.auth.decorators import login_required from django.http import Http404, JsonResponse from django.views.decorators.http import require_http_methods from review_agent.models import Conversation, FileAttachment from review_agent.models import FileSummaryBatch, WorkflowEvent from .events import serialize_event from .storage import save_uploaded_attachment, serialize_attachment def _conversation_for_user(user, conversation_id: int) -> Conversation: conversation = Conversation.objects.filter(pk=conversation_id, user=user).first() if not conversation: raise Http404("对话不存在。") return conversation @require_http_methods(["POST", "GET"]) @login_required def attachments(request, conversation_id: int): conversation = _conversation_for_user(request.user, conversation_id) if request.method == "POST": files = request.FILES.getlist("files") if not files: return JsonResponse({"error": "请选择至少一个文件。"}, status=400) saved = [ save_uploaded_attachment( conversation=conversation, user=request.user, uploaded_file=uploaded_file, ) for uploaded_file in files ] return JsonResponse({"attachments": [serialize_attachment(item) for item in saved]}) queryset = FileAttachment.objects.filter(conversation=conversation).order_by( "original_name", "-version_no", ) return JsonResponse({"attachments": [serialize_attachment(item) for item in queryset]}) @require_http_methods(["DELETE"]) @login_required def attachment_detail(request, conversation_id: int, attachment_id: int): conversation = _conversation_for_user(request.user, conversation_id) attachment = FileAttachment.objects.filter( pk=attachment_id, conversation=conversation, user=request.user, ).first() if not attachment: raise Http404("附件不存在。") attachment.upload_status = FileAttachment.UploadStatus.DELETED attachment.is_active = False attachment.save(update_fields=["upload_status", "is_active"]) return JsonResponse({"ok": True, "attachment": serialize_attachment(attachment)}) @require_http_methods(["GET"]) @login_required def batch_status(request, batch_id: int): batch = FileSummaryBatch.objects.filter(pk=batch_id, user=request.user).first() if not batch: raise Http404("批次不存在。") return JsonResponse( { "batch": { "id": batch.pk, "batch_no": batch.batch_no, "status": batch.status, "product_name": batch.product_name, "total_files": batch.total_files, "success_files": batch.success_files, "failed_files": batch.failed_files, "total_pages": batch.total_pages, }, "nodes": [ { "node_code": node.node_code, "node_name": node.node_name, "status": node.status, "progress": node.progress, "message": node.message, } for node in batch.node_runs.order_by("id") ], } ) @require_http_methods(["GET"]) @login_required def batch_events(request, batch_id: int): batch = FileSummaryBatch.objects.filter(pk=batch_id, user=request.user).first() if not batch: raise Http404("批次不存在。") after = request.GET.get("after") or "0" try: after_id = int(after) except ValueError: after_id = 0 events = WorkflowEvent.objects.filter(batch=batch, pk__gt=after_id).order_by("id") return JsonResponse({"events": [serialize_event(event) for event in events]})