feat: 飞书知识库读写工具:增删查改节点、写入页面、创建早报、记录踩坑,基于 tenant_access_token(修复表格写入顺序)
This commit is contained in:
+49
-46
@@ -48,57 +48,20 @@ def write_blocks(node_token, blocks):
|
|||||||
headers=h, json={'start_index': 0, 'end_index': len(cids)}
|
headers=h, json={'start_index': 0, 'end_index': len(cids)}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Separate table groups from normal blocks
|
# Write blocks in source order: normal blocks interleaved with tables
|
||||||
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
|
|
||||||
batch_size = 25
|
batch_size = 25
|
||||||
for idx in range(0, len(normal_blocks), batch_size):
|
|
||||||
batch = normal_blocks[idx:idx + batch_size]
|
def write_normal_batch(batch):
|
||||||
|
for idx in range(0, len(batch), batch_size):
|
||||||
|
chunk = batch[idx:idx + batch_size]
|
||||||
r = requests.post(
|
r = requests.post(
|
||||||
f'https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks/{doc_id}/children',
|
f'https://open.feishu.cn/open-apis/docx/v1/documents/{doc_id}/blocks/{doc_id}/children',
|
||||||
headers=h, json={'children': batch, 'index': -1}
|
headers=h, json={'children': chunk, 'index': -1}
|
||||||
)
|
)
|
||||||
if r.json().get('code') != 0:
|
if r.json().get('code') != 0:
|
||||||
raise Exception(f"Write batch {idx // batch_size} failed: {r.json().get('msg')}")
|
raise Exception(f"Write batch failed: {r.json().get('msg')}")
|
||||||
|
|
||||||
# Write table groups via descendant API
|
def write_table_group(group):
|
||||||
for group_idx, group in enumerate(table_groups):
|
|
||||||
table_block = group[0]
|
table_block = group[0]
|
||||||
descendants = [strip_table_meta(b) for b in group]
|
descendants = [strip_table_meta(b) for b in group]
|
||||||
table_bid = table_block.get('block_id', table_block.get('children', [''])[0])
|
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()
|
rd = r.json()
|
||||||
if rd.get('code') != 0:
|
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
|
return True
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user