// Node.js 22 has built-in fetch const APP_ID = 'cli_a93eb0f160399cc5'; const APP_SECRET = 'dRzJKrJ46j2Y1DKneyC33dQUNmsLwHCj'; const DOC_ID = 'YerQd8GomoDWQ6xA1zTc31xfnwb'; // 表格内容 (Markdown 格式) const TABLE_CONTENT = `| 日期 | 规格 | 数量 | |------|------|------| | 24 年 12 月 | 细和润 | 2 | | 24 年 12 月 | 金细 | 1 | | 24 年 12 月 | 红中支 | 3 | | 25 年 | 细和润 | 2 | | 25 年 | 双支 | 5 | **总计**: 13`; async function getTenantAccessToken() { const response = await fetch('https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ app_id: APP_ID, app_secret: APP_SECRET, }), }); const data = await response.json(); if (data.code !== 0) { throw new Error(`Failed to get access token: ${data.msg}`); } return data.tenant_access_token; } async function getDocumentInfo(token, docId) { // 获取文档信息 const response = await fetch(`https://open.feishu.cn/open-apis/docx/v1/documents/${docId}`, { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, }, }); const data = await response.json(); return { response, data }; } async function getDocumentBlocks(token, docId) { // 获取文档所有块 const response = await fetch(`https://open.feishu.cn/open-apis/docx/v1/documents/${docId}/blocks?page_size=100`, { method: 'GET', headers: { 'Authorization': `Bearer ${token}`, }, }); const data = await response.json(); return { response, data }; } async function appendBlock(token, docId, parentId, blockType, content) { // 在指定父块后添加子块 const response = await fetch(`https://open.feishu.cn/open-apis/docx/v1/documents/${docId}/blocks/${parentId}/children`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ blocks: [ { block_type: blockType, text: { elements: [ { text_run: { content: content, }, }, ], }, }, ], }), }); const data = await response.json(); return { response, data }; } async function main() { try { console.log('正在获取访问令牌...'); const token = await getTenantAccessToken(); console.log('✓ 获取访问令牌成功'); console.log('正在获取文档信息...'); const docInfo = await getDocumentInfo(token, DOC_ID); if (!docInfo.response.ok) { console.error('✗ 获取文档信息失败'); console.error('状态码:', docInfo.response.status); console.error('错误:', JSON.stringify(docInfo.data, null, 2)); return; } console.log('✓ 文档信息:', JSON.stringify(docInfo.data.data, null, 2)); console.log('正在获取文档块...'); const blocksInfo = await getDocumentBlocks(token, DOC_ID); if (!blocksInfo.response.ok) { console.error('✗ 获取文档块失败'); console.error('状态码:', blocksInfo.response.status); console.error('错误:', JSON.stringify(blocksInfo.data, null, 2)); return; } console.log('✓ 文档块数量:', blocksInfo.data.data?.items?.length || 0); if (blocksInfo.data.data?.items?.length > 0) { console.log('第一个块:', JSON.stringify(blocksInfo.data.data.items[0], null, 2)); } // 获取根块 ID const rootBlockId = blocksInfo.data.data?.items?.[0]?.block_id; if (!rootBlockId) { console.error('✗ 无法获取根块 ID'); return; } console.log('正在追加内容到文档...'); const result = await appendBlock(token, DOC_ID, rootBlockId, 1, TABLE_CONTENT); if (result.response.ok) { console.log('✓ 文档更新成功!'); console.log('响应:', JSON.stringify(result.data, null, 2)); } else { console.error('✗ 文档更新失败'); console.error('状态码:', result.response.status); console.error('错误:', JSON.stringify(result.data, null, 2)); } } catch (error) { console.error('✗ 发生错误:', error.message); console.error(error.stack); process.exit(1); } } main();