Spaces:
Sleeping
Sleeping
debug style
Browse files- sheet_service.py +82 -82
sheet_service.py
CHANGED
|
@@ -386,85 +386,85 @@ class SheetService:
|
|
| 386 |
return False
|
| 387 |
|
| 388 |
def batch_update_cells(self, sheet_url: str, update_data: list[dict]) -> dict | None:
|
| 389 |
-
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
|
|
|
| 386 |
return False
|
| 387 |
|
| 388 |
def batch_update_cells(self, sheet_url: str, update_data: list[dict]) -> dict | None:
|
| 389 |
+
"""
|
| 390 |
+
批次更新 Google Sheet 中的多個儲存格。
|
| 391 |
+
|
| 392 |
+
Args:
|
| 393 |
+
sheet_url (str): Google Sheet 的 URL。
|
| 394 |
+
update_data (list[dict]): 一個字典列表,每個字典應包含:
|
| 395 |
+
'range' (str): 要更新的範圍 (例如 '工作表名!A1')
|
| 396 |
+
'values' (list[list[str]]): 要寫入的值 (二維列表, 例如 [['value1']])
|
| 397 |
+
|
| 398 |
+
Returns:
|
| 399 |
+
dict | None: Google API 的返回結果,如果成功。否則返回 None。
|
| 400 |
+
"""
|
| 401 |
+
spreadsheet_id, _ = self._extract_ids_from_url(sheet_url)
|
| 402 |
+
if not spreadsheet_id:
|
| 403 |
+
logging.error(f"錯誤:無法從 URL {sheet_url} 中提取 Spreadsheet ID 進行批次更新。")
|
| 404 |
+
return None
|
| 405 |
+
if not self.service:
|
| 406 |
+
logging.error("Sheet API 服務未成功初始化。")
|
| 407 |
+
return None
|
| 408 |
+
if not update_data:
|
| 409 |
+
logging.warning("沒有需要批次更新的資料。")
|
| 410 |
+
return None
|
| 411 |
+
|
| 412 |
+
body = {
|
| 413 |
+
'valueInputOption': 'USER_ENTERED', # 或者 'RAW'
|
| 414 |
+
'data': []
|
| 415 |
+
}
|
| 416 |
+
valid_updates_count = 0 # 計算實際加入請求的數量
|
| 417 |
+
for item in update_data:
|
| 418 |
+
# 修正 1: 檢查 'values' 而不是 'value',並檢查 'values' 是否為列表
|
| 419 |
+
if 'range' not in item or 'values' not in item or not isinstance(item['values'], list):
|
| 420 |
+
logging.warning(f"跳過格式錯誤的更新項目 (缺少 'range' 或 'values' 非列表): {item}")
|
| 421 |
+
continue
|
| 422 |
+
# 修正 2: 稍微改進範圍檢查,確保 '!' 後面有內容
|
| 423 |
+
range_parts = item['range'].split('!', 1) # 最多分割一次
|
| 424 |
+
if len(range_parts) != 2 or not range_parts[0] or not range_parts[1]:
|
| 425 |
+
logging.warning(f"跳過範圍格式錯誤的更新項目 (格式應為 'SheetName!A1'): {item['range']}")
|
| 426 |
+
continue
|
| 427 |
+
|
| 428 |
+
# 修正 3: 直接使用 item['values'],它本身就應該是二維列表
|
| 429 |
+
body['data'].append({
|
| 430 |
+
'range': item['range'],
|
| 431 |
+
'values': item['values'] # 直接使用傳入的二維列表
|
| 432 |
+
})
|
| 433 |
+
valid_updates_count += 1
|
| 434 |
+
|
| 435 |
+
# 修正 4: 根據實際加入請求的數量判斷是否繼續
|
| 436 |
+
if not body['data']: # 或者 if valid_updates_count == 0:
|
| 437 |
+
logging.warning("經過驗證後,沒有有效的資料可以進行批次更新。")
|
| 438 |
+
# 即使沒有資料,也返回一個表示「沒有執行」的狀態,而不是 None,避免呼叫方誤判
|
| 439 |
+
# 或者可以返回一個特定的物件或空字典來表示未執行
|
| 440 |
+
return {"totalUpdatedCells": 0, "replies": [], "message": "No valid data to update after validation."} # 返回模擬的回應
|
| 441 |
+
|
| 442 |
+
try:
|
| 443 |
+
# logging.info(f"準備批次更新 Spreadsheet ID: {spreadsheet_id},共 {len(body['data'])} 個儲存格...")
|
| 444 |
+
# 使用 valid_updates_count 進行日誌記錄更準確
|
| 445 |
+
logging.info(f"準備批次更新 Spreadsheet ID: {spreadsheet_id},共 {valid_updates_count} 個有效儲存格...")
|
| 446 |
+
result = self.service.spreadsheets().values().batchUpdate(
|
| 447 |
+
spreadsheetId=spreadsheet_id,
|
| 448 |
+
body=body
|
| 449 |
+
).execute()
|
| 450 |
+
total_updated = result.get('totalUpdatedCells', 0)
|
| 451 |
+
logging.info(f"批次更新完成。API 回報共更新了 {total_updated} 個儲存格。")
|
| 452 |
+
# 可以在這裡比較 total_updated 和 valid_updates_count
|
| 453 |
+
if total_updated != valid_updates_count:
|
| 454 |
+
logging.warning(f"預期更新 {valid_updates_count} 個儲存格,但 API 回報更新了 {total_updated} 個。")
|
| 455 |
+
return result # 返回實際的 API 回應
|
| 456 |
+
except googleapiclient.errors.HttpError as error: # 更具體地捕獲 HttpError
|
| 457 |
+
error_details = error.resp.get('content', '{}')
|
| 458 |
+
try:
|
| 459 |
+
error_json = json.loads(error_details)
|
| 460 |
+
error_message = error_json.get('error', {}).get('message', str(error))
|
| 461 |
+
except json.JSONDecodeError:
|
| 462 |
+
error_message = str(error)
|
| 463 |
+
logging.error(f"批次更新儲存格時發生 API 錯誤 (ID: {spreadsheet_id}): {error_message}")
|
| 464 |
+
logging.error(f"錯誤詳情: {error.content.decode()}") # 打印詳細錯誤內容
|
| 465 |
+
return None # API 錯誤返回 None
|
| 466 |
+
except Exception as e:
|
| 467 |
+
logging.error(f"批次更新儲存格時發生未知錯誤: {e}")
|
| 468 |
+
import traceback
|
| 469 |
+
traceback.print_exc()
|
| 470 |
+
return None # 其他錯誤返回 None
|