|
|
@@ -0,0 +1,207 @@
|
|
|
+"""管理端 API:工作台、台账办理、配置、附件上传。"""
|
|
|
+from typing import Annotated, Optional
|
|
|
+
|
|
|
+from fastapi import APIRouter, Depends, File, Form, Query, UploadFile
|
|
|
+from sqlalchemy.orm import Session
|
|
|
+
|
|
|
+from app.core import storage
|
|
|
+from app.core.database import get_db
|
|
|
+from app.core.deps import get_current_user, require_menu
|
|
|
+from app.core.response import AppHTTPError, success_response
|
|
|
+from app.core.storage import StorageError
|
|
|
+from app.crud import attachment as attachment_crud
|
|
|
+from app.models.system import SysUser
|
|
|
+from app.schemas.business import HotlineUpdateBody, QrcodeUpdateBody, StatusUpdateBody
|
|
|
+from app.services import admin_ledger_service, config_service, dashboard_service
|
|
|
+
|
|
|
+router = APIRouter(prefix="/web/admin", tags=["admin"])
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/dashboard")
|
|
|
+def dashboard(
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ _user: Annotated[SysUser, Depends(get_current_user)],
|
|
|
+):
|
|
|
+ return success_response(dashboard_service.get_dashboard(db))
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/feedbacks")
|
|
|
+def list_feedbacks(
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ _user: Annotated[SysUser, Depends(get_current_user)],
|
|
|
+ status: Optional[str] = Query(None),
|
|
|
+ fbType: Optional[str] = Query(None),
|
|
|
+ keyword: Optional[str] = Query(None),
|
|
|
+ page: int = Query(1, ge=1),
|
|
|
+ pageSize: int = Query(10, ge=1, le=100),
|
|
|
+):
|
|
|
+ return success_response(
|
|
|
+ admin_ledger_service.list_feedbacks_page(
|
|
|
+ db,
|
|
|
+ status=status,
|
|
|
+ fb_type=fbType,
|
|
|
+ keyword=keyword,
|
|
|
+ page=page,
|
|
|
+ page_size=pageSize,
|
|
|
+ )
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/feedbacks/{feedback_id}")
|
|
|
+def get_feedback(
|
|
|
+ feedback_id: str,
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ _user: Annotated[SysUser, Depends(get_current_user)],
|
|
|
+):
|
|
|
+ return success_response(
|
|
|
+ admin_ledger_service.get_feedback_detail(db, feedback_id)
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@router.put("/feedbacks/{feedback_id}/status")
|
|
|
+def update_feedback_status(
|
|
|
+ feedback_id: str,
|
|
|
+ body: StatusUpdateBody,
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ user: Annotated[SysUser, Depends(require_menu("feedback:handle"))],
|
|
|
+):
|
|
|
+ return success_response(
|
|
|
+ admin_ledger_service.update_feedback_status(
|
|
|
+ db,
|
|
|
+ user,
|
|
|
+ feedback_id,
|
|
|
+ status=body.status,
|
|
|
+ handle_remark=body.handle_remark,
|
|
|
+ )
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/suggestions")
|
|
|
+def list_suggestions(
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ _user: Annotated[SysUser, Depends(get_current_user)],
|
|
|
+ status: Optional[str] = Query(None),
|
|
|
+ keyword: Optional[str] = Query(None),
|
|
|
+ page: int = Query(1, ge=1),
|
|
|
+ pageSize: int = Query(10, ge=1, le=100),
|
|
|
+):
|
|
|
+ return success_response(
|
|
|
+ admin_ledger_service.list_suggestions_page(
|
|
|
+ db,
|
|
|
+ status=status,
|
|
|
+ keyword=keyword,
|
|
|
+ page=page,
|
|
|
+ page_size=pageSize,
|
|
|
+ )
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/suggestions/{suggestion_id}")
|
|
|
+def get_suggestion(
|
|
|
+ suggestion_id: str,
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ _user: Annotated[SysUser, Depends(get_current_user)],
|
|
|
+):
|
|
|
+ return success_response(
|
|
|
+ admin_ledger_service.get_suggestion_detail(db, suggestion_id)
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@router.put("/suggestions/{suggestion_id}/status")
|
|
|
+def update_suggestion_status(
|
|
|
+ suggestion_id: str,
|
|
|
+ body: StatusUpdateBody,
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ user: Annotated[SysUser, Depends(require_menu("suggestion:handle"))],
|
|
|
+):
|
|
|
+ return success_response(
|
|
|
+ admin_ledger_service.update_suggestion_status(
|
|
|
+ db,
|
|
|
+ user,
|
|
|
+ suggestion_id,
|
|
|
+ status=body.status,
|
|
|
+ handle_remark=body.handle_remark,
|
|
|
+ )
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/hotline")
|
|
|
+def get_hotline(
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ _user: Annotated[SysUser, Depends(get_current_user)],
|
|
|
+):
|
|
|
+ return success_response(config_service.get_hotline_payload(db))
|
|
|
+
|
|
|
+
|
|
|
+@router.put("/hotline")
|
|
|
+def put_hotline(
|
|
|
+ body: HotlineUpdateBody,
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ user: Annotated[SysUser, Depends(require_menu("hotline:write"))],
|
|
|
+):
|
|
|
+ return success_response(
|
|
|
+ config_service.update_hotline(
|
|
|
+ db,
|
|
|
+ user,
|
|
|
+ phone=body.phone,
|
|
|
+ email=body.email,
|
|
|
+ address=body.address,
|
|
|
+ work_time=body.work_time,
|
|
|
+ )
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@router.get("/qrcode")
|
|
|
+def get_qrcode(
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ _user: Annotated[SysUser, Depends(get_current_user)],
|
|
|
+):
|
|
|
+ return success_response(config_service.get_qrcode_payload(db))
|
|
|
+
|
|
|
+
|
|
|
+@router.put("/qrcode")
|
|
|
+def put_qrcode(
|
|
|
+ body: QrcodeUpdateBody,
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ user: Annotated[SysUser, Depends(require_menu("qrcode:write"))],
|
|
|
+):
|
|
|
+ return success_response(
|
|
|
+ config_service.update_qrcode(
|
|
|
+ db,
|
|
|
+ user,
|
|
|
+ land_url=body.land_url,
|
|
|
+ title=body.title,
|
|
|
+ image_url=body.image_url,
|
|
|
+ )
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+@router.post("/attachment/upload")
|
|
|
+async def admin_upload(
|
|
|
+ db: Annotated[Session, Depends(get_db)],
|
|
|
+ _user: Annotated[SysUser, Depends(get_current_user)],
|
|
|
+ file: UploadFile = File(...),
|
|
|
+ folder: Optional[str] = Form(""),
|
|
|
+):
|
|
|
+ if not file or not file.filename:
|
|
|
+ raise AppHTTPError(400, "请选择文件")
|
|
|
+ content = await file.read()
|
|
|
+ try:
|
|
|
+ stored = storage.upload_file(content, file.filename, folder or "")
|
|
|
+ except StorageError as exc:
|
|
|
+ raise AppHTTPError(400, exc.message) from exc
|
|
|
+ row = attachment_crud.create_attachment(
|
|
|
+ db,
|
|
|
+ file_name=file.filename,
|
|
|
+ object_key=stored["objectKey"],
|
|
|
+ url=stored["url"],
|
|
|
+ size=len(content),
|
|
|
+ )
|
|
|
+ return success_response(
|
|
|
+ {
|
|
|
+ "id": row.id,
|
|
|
+ "url": row.url,
|
|
|
+ "fileName": row.file_name,
|
|
|
+ "size": row.size,
|
|
|
+ }
|
|
|
+ )
|