From f36a2b60596d80e5abcb0a59b93e2abc8d95087d Mon Sep 17 00:00:00 2001 From: Pine Date: Wed, 9 Sep 2026 01:51:38 +0800 Subject: [PATCH] =?UTF-8?q?admin/tasks=EF=BC=9A=E6=89=80=E6=9C=89=E5=8F=AF?= =?UTF-8?q?=E7=A9=BA=E5=A4=96=E9=94=AE/=E5=85=B3=E8=81=94=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=A9=BA=E4=B8=B2=E7=BB=9F=E4=B8=80=E8=BD=AC=20NULL?= =?UTF-8?q?=20=E9=98=B2=201452?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 前端未填 publisher_id 时传空字符串违反 tasks_ibfk_3(publisher_id→users.id)外键, 与 category_id 同类问题。将可空关联字段(publisher_id/publisher_org_id/claimed_by/ assign_park_id/assign_opc_id/park_id/category_id 及可空时间字段)统一清洗为 NULL; NOT NULL 列(deadline/published_at 等)保留空串原样,避免 1048 --- app/api/routers/rbac_operator.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/app/api/routers/rbac_operator.py b/app/api/routers/rbac_operator.py index 197a8a4..37dd044 100644 --- a/app/api/routers/rbac_operator.py +++ b/app/api/routers/rbac_operator.py @@ -321,11 +321,10 @@ async def create_task( ): fields = req.model_dump(exclude_none=True) fields["mode"] = _normalize_mode(fields.get("mode", "grab")) - # 空分类/空截止 → NULL:外键列可空,避免空字符串违反 tasks_ibfk_1 约束(500) - if not fields.get("category_id"): - fields["category_id"] = None - if not fields.get("deadline"): - fields["deadline"] = None + # 空字符串关联/外键/日期字段 → NULL:列均可空,避免空串违反 tasks_ibfk_* 外键约束(500) + for _fk in _TASK_NULLABLE_FIELDS: + if not fields.get(_fk): + fields[_fk] = None if not fields.get("task_code"): fields["task_code"] = _gen_task_code() task = await db.tasks.create(fields) @@ -341,6 +340,18 @@ def _normalize_mode(mode: str) -> str: return m if m in ("grab", "bid", "assign", "recommend") else "grab" +# 任务表可空列中的关联/外键字段:前端未填时传空字符串会触发外键约束失败(1452),统一清洗为 NULL。 +# 注意:仅限 nullable=YES 的列(deadline/published_at/claimed_at 等 NOT NULL 列保留空串原样)。 +_TASK_NULLABLE_FIELDS = ( + "category_id", # FK task_categories.id(tasks_ibfk_1) + "publisher_id", # FK users.id(tasks_ibfk_3) + "publisher_org_id", # FK organizations.id + "claimed_by", # FK users.id(接单人) + "assign_park_id", "assign_opc_id", "park_id", # 指派/归属(可空) + "assigned_at", "signed_at", "on_time", # 可空时间/状态字段 +) + + @router.patch("/tasks/{task_id}", summary="更新任务(增改)") async def update_task( task_id: str, @@ -352,11 +363,10 @@ async def update_task( if await db.tasks.get(task_id) is None: raise HTTPException(status_code=404, detail="Task not found") patch = req.model_dump(exclude_none=True) - # 空分类/空截止 → NULL(同 create 容错,避免外键 500) - if not patch.get("category_id"): - patch["category_id"] = None - if not patch.get("deadline"): - patch["deadline"] = None + # 空字符串关联/外键/日期字段 → NULL(同 create 容错,避免外键 500) + for _fk in _TASK_NULLABLE_FIELDS: + if not patch.get(_fk): + patch[_fk] = None task = await db.tasks.update(task_id, patch) await write_audit(db, action="task.update", resource="task", resource_id=task_id, detail=(req.title or ""), user=actor, request=request)