feat(calendar): add drag-and-drop to assign unknown bangumi to weekdays

Allow users to drag bangumi cards from the "Unknown" section into weekday
columns in the calendar view. Manual assignments are locked so calendar
refresh from Bangumi.tv doesn't overwrite them. A reset button lets users
unlock and send cards back to Unknown.

Backend:
- Add weekday_locked field to Bangumi model (migration v9)
- Add PATCH /api/v1/bangumi/{id}/weekday endpoint
- Skip locked items in refresh_calendar()

Frontend:
- Add vuedraggable for smooth drag-and-drop
- Pin indicator and unpin button on manually-assigned cards
- Drop zone highlighting during drag
- i18n strings for drag/pin/unpin

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Estrella Pan
2026-02-23 14:21:00 +01:00
parent 326d31dd0f
commit a0bf878b7e
15 changed files with 774 additions and 81 deletions

View File

@@ -41,6 +41,10 @@ class OffsetSuggestionDetail(BaseModel):
confidence: Literal["high", "medium", "low"]
class SetWeekdayRequest(BaseModel):
weekday: Optional[int] = None # 0-6 for Mon-Sun, None to reset
class DetectOffsetRequest(BaseModel):
"""Request body for detect-offset endpoint."""
title: str
@@ -339,3 +343,41 @@ async def get_needs_review():
"""Get all bangumi that need review for offset mismatch."""
with Database() as db:
return db.bangumi.get_needs_review()
@router.patch(
path="/{bangumi_id}/weekday",
response_model=APIResponse,
dependencies=[Depends(get_current_user)],
)
async def set_weekday(bangumi_id: int, request: SetWeekdayRequest):
"""Manually set the broadcast weekday for a bangumi."""
if request.weekday is not None and not (0 <= request.weekday <= 6):
return JSONResponse(
status_code=400,
content={
"status": False,
"msg_en": "Weekday must be 0-6 (Mon-Sun) or null.",
"msg_zh": "星期必须是 0-6周一至周日或空。",
},
)
with Database() as db:
success = db.bangumi.set_weekday(bangumi_id, request.weekday)
if success:
action = f"weekday {request.weekday}" if request.weekday is not None else "unknown"
return JSONResponse(
status_code=200,
content={
"status": True,
"msg_en": f"Set bangumi to {action}.",
"msg_zh": f"已设置放送日为 {action}",
},
)
return JSONResponse(
status_code=404,
content={
"status": False,
"msg_en": f"Bangumi {bangumi_id} not found.",
"msg_zh": f"未找到番剧 {bangumi_id}",
},
)