|
@@ -310,6 +310,30 @@ def upload_to_feishu(csv_file, sheet_token, sheet_id=None, sort_spec="dt:desc",
|
|
|
current_cols = sheet_props['column_count'] if sheet_props else 26
|
|
current_cols = sheet_props['column_count'] if sheet_props else 26
|
|
|
header_end_col = column_index_to_letter(current_cols)
|
|
header_end_col = column_index_to_letter(current_cols)
|
|
|
|
|
|
|
|
|
|
+ # 扩展列数(CSV 列数超过当前 sheet 列数时)
|
|
|
|
|
+ num_csv_cols = len(header)
|
|
|
|
|
+ if num_csv_cols > current_cols:
|
|
|
|
|
+ add_cols = num_csv_cols - current_cols
|
|
|
|
|
+ expand_headers = {
|
|
|
|
|
+ 'Content-Type': 'application/json; charset=utf-8',
|
|
|
|
|
+ 'Authorization': f'Bearer {access_token}'
|
|
|
|
|
+ }
|
|
|
|
|
+ expand_payload = {
|
|
|
|
|
+ "dimension": {
|
|
|
|
|
+ "sheetId": sheet_id,
|
|
|
|
|
+ "majorDimension": "COLUMNS",
|
|
|
|
|
+ "length": add_cols
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ try:
|
|
|
|
|
+ request("POST", f"{LARK_HOST}/open-apis/sheets/v2/spreadsheets/{sheet_token}/dimension_range",
|
|
|
|
|
+ expand_headers, expand_payload)
|
|
|
|
|
+ print(f"扩展列数: {current_cols} -> {num_csv_cols} (+{add_cols}列)")
|
|
|
|
|
+ current_cols = num_csv_cols
|
|
|
|
|
+ header_end_col = column_index_to_letter(current_cols)
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f" 扩展列数失败: {e}")
|
|
|
|
|
+
|
|
|
# 读取飞书表头(获取所有列)
|
|
# 读取飞书表头(获取所有列)
|
|
|
feishu_header = client.read_range_values(access_token, sheet_token, f"{sheet_id}!A1:{header_end_col}1")
|
|
feishu_header = client.read_range_values(access_token, sheet_token, f"{sheet_id}!A1:{header_end_col}1")
|
|
|
feishu_cols = []
|
|
feishu_cols = []
|
|
@@ -348,12 +372,17 @@ def upload_to_feishu(csv_file, sheet_token, sheet_id=None, sort_spec="dt:desc",
|
|
|
header = feishu_cols
|
|
header = feishu_cols
|
|
|
print(f"已按飞书表头顺序重排数据")
|
|
print(f"已按飞书表头顺序重排数据")
|
|
|
else:
|
|
else:
|
|
|
- # 飞书表头为空,用 CSV 表头写入
|
|
|
|
|
|
|
+ # 飞书表头为空,用 CSV 表头写入(飞书单次最多写100列,需分批)
|
|
|
print(f"飞书表头为空,使用 CSV 表头写入")
|
|
print(f"飞书表头为空,使用 CSV 表头写入")
|
|
|
- header_range = f"{sheet_id}!A1:{column_index_to_letter(len(header))}1"
|
|
|
|
|
- client.batch_update_values(access_token, sheet_token, {
|
|
|
|
|
- "valueRanges": [{"range": header_range, "values": [header]}]
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ col_batch = 100
|
|
|
|
|
+ for start in range(0, len(header), col_batch):
|
|
|
|
|
+ end = min(start + col_batch, len(header))
|
|
|
|
|
+ start_col = column_index_to_letter(start + 1)
|
|
|
|
|
+ end_col = column_index_to_letter(end)
|
|
|
|
|
+ batch_range = f"{sheet_id}!{start_col}1:{end_col}1"
|
|
|
|
|
+ client.batch_update_values(access_token, sheet_token, {
|
|
|
|
|
+ "valueRanges": [{"range": batch_range, "values": [header[start:end]]}]
|
|
|
|
|
+ })
|
|
|
|
|
|
|
|
total_rows = len(converted_rows)
|
|
total_rows = len(converted_rows)
|
|
|
num_cols = len(header)
|
|
num_cols = len(header)
|
|
@@ -433,10 +462,18 @@ def upload_to_feishu(csv_file, sheet_token, sheet_id=None, sort_spec="dt:desc",
|
|
|
print(f" 插入行失败: {e}")
|
|
print(f" 插入行失败: {e}")
|
|
|
break
|
|
break
|
|
|
|
|
|
|
|
- # 写入数据到插入的行(第3行开始)
|
|
|
|
|
- range_str = f"{sheet_id}!A3:{end_col}{2 + batch_count}"
|
|
|
|
|
|
|
+ # 写入数据到插入的行(第3行开始,飞书单次最多100列,需按列分批)
|
|
|
|
|
+ col_batch = 100
|
|
|
|
|
+ value_ranges = []
|
|
|
|
|
+ for col_start in range(0, num_cols, col_batch):
|
|
|
|
|
+ col_end = min(col_start + col_batch, num_cols)
|
|
|
|
|
+ sc = column_index_to_letter(col_start + 1)
|
|
|
|
|
+ ec = column_index_to_letter(col_end)
|
|
|
|
|
+ col_range = f"{sheet_id}!{sc}3:{ec}{2 + batch_count}"
|
|
|
|
|
+ col_values = [row[col_start:col_end] for row in batch]
|
|
|
|
|
+ value_ranges.append({"range": col_range, "values": col_values})
|
|
|
client.batch_update_values(access_token, sheet_token, {
|
|
client.batch_update_values(access_token, sheet_token, {
|
|
|
- "valueRanges": [{"range": range_str, "values": batch}]
|
|
|
|
|
|
|
+ "valueRanges": value_ranges
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
processed += batch_count
|
|
processed += batch_count
|