package feishu_util import ( "context" "fmt" larkcore "github.com/larksuite/oapi-sdk-go/v3/core" larkwiki "github.com/larksuite/oapi-sdk-go/v3/service/wiki/v2" ) // WikiNode 知识库节点解析结果。 type WikiNode struct { SpaceID string NodeToken string ObjToken string ObjType string Title string } // ResolveWikiNode 通过知识库 node_token 获取实际云文档 obj_token。 // 知识库 URL 中的 token 不是 spreadsheet_token,读写表格内容前必须先转换。 func (c *Client) ResolveWikiNode(ctx context.Context, wikiToken string) (*WikiNode, error) { if wikiToken == "" { return nil, fmt.Errorf("wikiToken 为空") } req := larkwiki.NewGetNodeSpaceReqBuilder(). Token(wikiToken). Build() resp, err := c.Lark.Wiki.V2.Space.GetNode(ctx, req) if err != nil { return nil, fmt.Errorf("获取知识库节点失败: %w", err) } if !resp.Success() { return nil, fmt.Errorf("获取知识库节点失败: code=%d msg=%s log_id=%s detail=%s", resp.Code, resp.Msg, resp.RequestId(), larkcore.Prettify(resp.CodeError)) } if resp.Data == nil || resp.Data.Node == nil { return nil, fmt.Errorf("获取知识库节点返回空数据") } n := resp.Data.Node node := &WikiNode{} if n.SpaceId != nil { node.SpaceID = *n.SpaceId } if n.NodeToken != nil { node.NodeToken = *n.NodeToken } if n.ObjToken != nil { node.ObjToken = *n.ObjToken } if n.ObjType != nil { node.ObjType = *n.ObjType } if n.Title != nil { node.Title = *n.Title } if node.ObjToken == "" { return nil, fmt.Errorf("知识库节点未返回 obj_token") } return node, nil } // ResolveSpreadsheetToken 将 SpreadsheetRef 解析为可调用 Sheets API 的 spreadsheet_token。 func (c *Client) ResolveSpreadsheetToken(ctx context.Context, ref *SpreadsheetRef) (string, error) { if ref == nil { return "", fmt.Errorf("SpreadsheetRef 为空") } if ref.SpreadsheetToken != "" { return ref.SpreadsheetToken, nil } if ref.WikiToken == "" { return "", fmt.Errorf("既无 SpreadsheetToken 也无 WikiToken") } node, err := c.ResolveWikiNode(ctx, ref.WikiToken) if err != nil { return "", err } if node.ObjType != "" && node.ObjType != "sheet" { return "", fmt.Errorf("知识库节点类型为 %s,不是电子表格(sheet)", node.ObjType) } ref.SpreadsheetToken = node.ObjToken return node.ObjToken, nil }