feat: 飞书知识库读写工具:增删查改节点、写入页面、创建早报、记录踩坑,基于 tenant_access_token(修复表格写入顺序)
This commit is contained in:
+53
-50
@@ -48,57 +48,20 @@ def write_blocks(node_token, blocks):
|
||||
headers=h, json={'start_index': 0, 'end_index': len(cids)}
|
||||
)
|
||||
|
||||
# Separate table groups from normal blocks
|
||||
normal_blocks = []
|
||||
table_groups = []
|
||||
i = 0
|
||||
while i < len(blocks):
|
||||
b = blocks[i]
|
||||
if b.get('__table'):
|
||||
group = []
|
||||
table_prefix = b.get('block_id', '')
|
||||
j = i
|
||||
# Collect table + cells + cell content (all tagged with __table or have matching ecc_ block_id)
|
||||
while j < len(blocks):
|
||||
bj = blocks[j]
|
||||
bid = bj.get('block_id', '')
|
||||
# Same table group: __table marker, cell/child with matching prefix, or continuation
|
||||
if bj.get('__table') and j != i:
|
||||
break
|
||||
if bj.get('block_type') == 31 and not bj.get('__table'):
|
||||
break
|
||||
# Stop at unrelated blocks (non-table, non-cell blocks without matching prefix)
|
||||
if not bj.get('__table') and not bid.startswith('ecc_t'):
|
||||
# Only include empty text blocks with block_id (spacers next to table)
|
||||
if bj.get('block_type') == 2 and bid:
|
||||
elements = bj.get('text', {}).get('elements', [])
|
||||
if elements and all(e.get('text_run', {}).get('content', '') == '' for e in elements):
|
||||
pass # empty spacer included
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
group.append(bj)
|
||||
j += 1
|
||||
table_groups.append(group)
|
||||
i = j
|
||||
else:
|
||||
normal_blocks.append(b)
|
||||
i += 1
|
||||
|
||||
# Write normal blocks in batches
|
||||
# Write blocks in source order: normal blocks interleaved with tables
|
||||
batch_size = 25
|
||||
for idx in range(0, len(normal_blocks), batch_size):
|
||||
batch = normal_blocks[idx:idx + batch_size]
|
||||
r = requests.post(
|
||||
f'https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks/{doc_id}/children',
|
||||
headers=h, json={'children': batch, 'index': -1}
|
||||
)
|
||||
if r.json().get('code') != 0:
|
||||
raise Exception(f"Write batch {idx // batch_size} failed: {r.json().get('msg')}")
|
||||
|
||||
# Write table groups via descendant API
|
||||
for group_idx, group in enumerate(table_groups):
|
||||
def write_normal_batch(batch):
|
||||
for idx in range(0, len(batch), batch_size):
|
||||
chunk = batch[idx:idx + batch_size]
|
||||
r = requests.post(
|
||||
f'https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks/{doc_id}/children',
|
||||
headers=h, json={'children': chunk, 'index': -1}
|
||||
)
|
||||
if r.json().get('code') != 0:
|
||||
raise Exception(f"Write batch failed: {r.json().get('msg')}")
|
||||
|
||||
def write_table_group(group):
|
||||
table_block = group[0]
|
||||
descendants = [strip_table_meta(b) for b in group]
|
||||
table_bid = table_block.get('block_id', table_block.get('children', [''])[0])
|
||||
@@ -113,7 +76,47 @@ def write_blocks(node_token, blocks):
|
||||
)
|
||||
rd = r.json()
|
||||
if rd.get('code') != 0:
|
||||
raise Exception(f"Table {group_idx} descendant API failed: {rd.get('msg')}")
|
||||
raise Exception(f"Table descendant API failed: {rd.get('msg')}")
|
||||
|
||||
normal_batch = []
|
||||
i = 0
|
||||
while i < len(blocks):
|
||||
b = blocks[i]
|
||||
if b.get('__table'):
|
||||
# Flush pending normal blocks before the table to keep source order
|
||||
if normal_batch:
|
||||
write_normal_batch(normal_batch)
|
||||
normal_batch = []
|
||||
# Collect this table group: table + cells + cell content
|
||||
group = []
|
||||
j = i
|
||||
while j < len(blocks):
|
||||
bj = blocks[j]
|
||||
bid = bj.get('block_id', '')
|
||||
if bj.get('__table') and j != i:
|
||||
break
|
||||
if bj.get('block_type') == 31 and not bj.get('__table'):
|
||||
break
|
||||
if not bj.get('__table') and not bid.startswith('ecc_t'):
|
||||
if bj.get('block_type') == 2 and bid:
|
||||
elements = bj.get('text', {}).get('elements', [])
|
||||
if elements and all(e.get('text_run', {}).get('content', '') == '' for e in elements):
|
||||
pass # empty spacer included
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
group.append(bj)
|
||||
j += 1
|
||||
write_table_group(group)
|
||||
i = j
|
||||
else:
|
||||
normal_batch.append(b)
|
||||
i += 1
|
||||
|
||||
# Flush remaining normal blocks
|
||||
if normal_batch:
|
||||
write_normal_batch(normal_batch)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user