|
@@ -17,7 +17,8 @@ db_dependency = Depends(get_db_connection)
|
|
|
|
|
|
|
|
class BindCardRequest(BaseModel):
|
|
class BindCardRequest(BaseModel):
|
|
|
user_id: int = Field(..., ge=0)
|
|
user_id: int = Field(..., ge=0)
|
|
|
- card_id: List[int] = Field(..., min_length=1)
|
|
|
|
|
|
|
+ bind_card_id: List[int] = Field(default_factory=list)
|
|
|
|
|
+ unbind_card_id: List[int] = Field(default_factory=list)
|
|
|
|
|
|
|
|
|
|
|
|
|
def _auth_exception(detail: str = "用户认证信息无效") -> HTTPException:
|
|
def _auth_exception(detail: str = "用户认证信息无效") -> HTTPException:
|
|
@@ -96,33 +97,56 @@ def bind_card_to_user(
|
|
|
db_conn: PooledMySQLConnection = db_dependency
|
|
db_conn: PooledMySQLConnection = db_dependency
|
|
|
):
|
|
):
|
|
|
try:
|
|
try:
|
|
|
- # 请求字段保持 card_id,但支持一次绑定多个卡片,并自动去重。
|
|
|
|
|
- card_ids = list(dict.fromkeys(data.card_id))
|
|
|
|
|
|
|
+ # 先解绑再绑定;如果同一张卡同时出现在两个列表,最终以绑定列表为准。
|
|
|
|
|
+ bind_card_ids = list(dict.fromkeys(data.bind_card_id))
|
|
|
|
|
+ unbind_card_ids = list(dict.fromkeys(data.unbind_card_id))
|
|
|
|
|
+ operation_card_ids = list(dict.fromkeys(unbind_card_ids + bind_card_ids))
|
|
|
|
|
+
|
|
|
|
|
+ if not operation_card_ids:
|
|
|
|
|
+ raise HTTPException(status_code=400, detail="绑定列表和解绑列表不能同时为空")
|
|
|
|
|
|
|
|
with db_conn.cursor(dictionary=True) as cursor:
|
|
with db_conn.cursor(dictionary=True) as cursor:
|
|
|
- format_strings = ",".join(["%s"] * len(card_ids))
|
|
|
|
|
|
|
+ format_strings = ",".join(["%s"] * len(operation_card_ids))
|
|
|
cursor.execute(
|
|
cursor.execute(
|
|
|
f"SELECT id FROM `{settings.DB_CARD_TABLE_NAME}` WHERE id IN ({format_strings})",
|
|
f"SELECT id FROM `{settings.DB_CARD_TABLE_NAME}` WHERE id IN ({format_strings})",
|
|
|
- tuple(card_ids)
|
|
|
|
|
|
|
+ tuple(operation_card_ids)
|
|
|
)
|
|
)
|
|
|
existing_card_ids = {row["id"] for row in cursor.fetchall()}
|
|
existing_card_ids = {row["id"] for row in cursor.fetchall()}
|
|
|
- missing_card_ids = sorted(set(card_ids) - existing_card_ids)
|
|
|
|
|
|
|
+ missing_card_ids = sorted(set(operation_card_ids) - existing_card_ids)
|
|
|
if missing_card_ids:
|
|
if missing_card_ids:
|
|
|
raise HTTPException(status_code=404, detail=f"卡片未发现: {missing_card_ids}")
|
|
raise HTTPException(status_code=404, detail=f"卡片未发现: {missing_card_ids}")
|
|
|
|
|
|
|
|
- bind_params = [(data.user_id, card_id) for card_id in card_ids]
|
|
|
|
|
- cursor.executemany(
|
|
|
|
|
- f"INSERT IGNORE INTO `{settings.DB_USER_CARD_TABLE_NAME}` (user_id, card_id) VALUES (%s, %s)",
|
|
|
|
|
- bind_params
|
|
|
|
|
- )
|
|
|
|
|
- inserted_count = cursor.rowcount
|
|
|
|
|
|
|
+ deleted_count = 0
|
|
|
|
|
+ if unbind_card_ids:
|
|
|
|
|
+ unbind_format_strings = ",".join(["%s"] * len(unbind_card_ids))
|
|
|
|
|
+ cursor.execute(
|
|
|
|
|
+ f"DELETE FROM `{settings.DB_USER_CARD_TABLE_NAME}` "
|
|
|
|
|
+ f"WHERE user_id = %s AND card_id IN ({unbind_format_strings})",
|
|
|
|
|
+ tuple([data.user_id] + unbind_card_ids)
|
|
|
|
|
+ )
|
|
|
|
|
+ deleted_count = cursor.rowcount
|
|
|
|
|
+
|
|
|
|
|
+ inserted_count = 0
|
|
|
|
|
+ if bind_card_ids:
|
|
|
|
|
+ bind_params = [(data.user_id, card_id) for card_id in bind_card_ids]
|
|
|
|
|
+ cursor.executemany(
|
|
|
|
|
+ f"INSERT IGNORE INTO `{settings.DB_USER_CARD_TABLE_NAME}` (user_id, card_id) VALUES (%s, %s)",
|
|
|
|
|
+ bind_params
|
|
|
|
|
+ )
|
|
|
|
|
+ inserted_count = cursor.rowcount
|
|
|
|
|
+
|
|
|
db_conn.commit()
|
|
db_conn.commit()
|
|
|
|
|
|
|
|
- logger.info(f"Admin {current_user['id']} bound cards {card_ids} to external user {data.user_id}")
|
|
|
|
|
|
|
+ logger.info(
|
|
|
|
|
+ f"Admin {current_user['id']} updated card bindings for external user {data.user_id}: "
|
|
|
|
|
+ f"bind={bind_card_ids}, unbind={unbind_card_ids}"
|
|
|
|
|
+ )
|
|
|
return {
|
|
return {
|
|
|
- "message": "卡片绑定成功",
|
|
|
|
|
|
|
+ "message": "卡片绑定关系更新成功",
|
|
|
"user_id": data.user_id,
|
|
"user_id": data.user_id,
|
|
|
- "card_id": card_ids,
|
|
|
|
|
|
|
+ "bind_card_id": bind_card_ids,
|
|
|
|
|
+ "unbind_card_id": unbind_card_ids,
|
|
|
|
|
+ "deleted_count": deleted_count,
|
|
|
"inserted_count": inserted_count
|
|
"inserted_count": inserted_count
|
|
|
}
|
|
}
|
|
|
|
|
|