├── testdata ├── 1 │ ├── static │ │ ├── pending.png │ │ ├── boxcniB7OYCR0mmRx0kBAcfbZmc.jpg │ │ ├── boxcnx060XAN4NUm2doWRuGToWr.jpg │ │ └── boxcnyAEhNeanmSz2XhcK7ata0t.jpg │ ├── data.md │ └── data.json └── 2 │ ├── static │ ├── boxcn0HzjG37SyTpjU1yZf0KqPD.jpg │ ├── boxcn25PWN2On2MLOY5BWG7z1Hg.jpg │ ├── boxcn3lEjzi1dtjcW0HefP4S7xf.jpg │ ├── boxcn3xaJFpBpeHu6pAmWzOrtje.jpg │ ├── boxcn40Y8XbPNrVWhXFGVRLmbme.jpg │ ├── boxcn4wmVZNhV3lZkLjmGKZc5Md.jpg │ ├── boxcn5lChHrJaszJIyXnlgaz6Xg.jpg │ ├── boxcn6Vrm09Vc8VRZOJbWhTIigd.jpg │ ├── boxcn7ZWNAdXvg4UZbLWqBJf2yh.jpg │ ├── boxcn8OMM3d3GRkIgwnHc1hSCjh.jpg │ ├── boxcnADb2YDHqZm37TEACF98LtI.jpg │ ├── boxcnAHohD8jQYdeMYJMdeuZxkc.jpg │ ├── boxcnARhtVIowNIXDwo5QjFZnmh.jpg │ ├── boxcnC2Eg3D9X61sqbaJPB3Kp2f.jpg │ ├── boxcnCiUW4Qo1p2Qc6hfXo96VAe.jpg │ ├── boxcnFxR4HoSuuzrk6RYCVzCBOg.jpg │ ├── boxcnFyq7S9MamZsL36LGcOgOQe.jpg │ ├── boxcnGNXYmjel1Z2XoVRxK4kt6g.jpg │ ├── boxcnHQ1vvmYL22k9uKq5rkKZFb.jpg │ ├── boxcnJg137wnmKcJ5BgDDnfgQ2n.jpg │ ├── boxcnKwIOri3Lt1DmnoKDbxIoBd.jpg │ ├── boxcnPevppqdMDOuENHwQ39NLQ0.jpg │ ├── boxcnU4jh8M4Je3HH9hkrm8Ouvg.jpg │ ├── boxcnYiBn8uesGTe4ZOmwXqhmOc.jpg │ ├── boxcnZd087QeiMwEXhESnXKsaGh.jpg │ ├── boxcna1WNPAzBk8jMDm7fgLDUah.jpg │ ├── boxcna7jKR0D2waFy8b1h1Mn9sh.jpg │ ├── boxcnfUN5uriCMTVxhTO3JUIgmf.jpg │ ├── boxcng4vXnqf40s8biMrNZJIyHg.jpg │ ├── boxcnhRvghde8oV88siXY6HEJdb.jpg │ ├── boxcnj0jnTpqsT2psX4PjN7RdUc.jpg │ ├── boxcnkpN3TF5YXEVjpbgJ48gzQb.jpg │ ├── boxcnmheXItwGdTJR6YY3VCmWlb.jpg │ ├── boxcnn8lcAoQJkdADTdsktG3uhj.jpg │ ├── boxcnni357jaooOc8dyVZgwOT0f.jpg │ ├── boxcnoEPle5mVh1MCEOAeCd78Kg.jpg │ ├── boxcnoL6TtwSadFAq0JdJyQQ8Rg.jpg │ ├── boxcnoVfyT94NXsCjur6xnLGEfb.jpg │ ├── boxcnqYLIQq0QByyf3UvEWc0jug.jpg │ ├── boxcnunibrea2QMPlGTnUYyK9dh.jpg │ ├── boxcnvy8YGoxrsZiEB3OuOtV76e.jpg │ ├── boxcnwIP4hJADL0BfDkiO0EJcQ9.jpg │ ├── boxcnwl8p1SpMmjVjdDXcmQtRfd.jpg │ └── boxcnzb83lR9jSX5BQZlYIkvVac.jpg │ └── data.md ├── .gitignore ├── go.mod ├── .github ├── test.sh ├── dependabot.yml └── workflows │ ├── release.yml │ ├── codestyle-check.yml │ ├── test.yml │ └── codeql-analysis.yml ├── .goreleaser.yml ├── _examples └── main.go ├── static.go ├── go.sum ├── README.md ├── md_test.go ├── md.go └── LICENSE /testdata/1/static/pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/1/static/pending.png -------------------------------------------------------------------------------- /testdata/1/static/boxcniB7OYCR0mmRx0kBAcfbZmc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/1/static/boxcniB7OYCR0mmRx0kBAcfbZmc.jpg -------------------------------------------------------------------------------- /testdata/1/static/boxcnx060XAN4NUm2doWRuGToWr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/1/static/boxcnx060XAN4NUm2doWRuGToWr.jpg -------------------------------------------------------------------------------- /testdata/1/static/boxcnyAEhNeanmSz2XhcK7ata0t.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/1/static/boxcnyAEhNeanmSz2XhcK7ata0t.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn0HzjG37SyTpjU1yZf0KqPD.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn0HzjG37SyTpjU1yZf0KqPD.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn25PWN2On2MLOY5BWG7z1Hg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn25PWN2On2MLOY5BWG7z1Hg.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn3lEjzi1dtjcW0HefP4S7xf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn3lEjzi1dtjcW0HefP4S7xf.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn3xaJFpBpeHu6pAmWzOrtje.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn3xaJFpBpeHu6pAmWzOrtje.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn40Y8XbPNrVWhXFGVRLmbme.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn40Y8XbPNrVWhXFGVRLmbme.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn4wmVZNhV3lZkLjmGKZc5Md.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn4wmVZNhV3lZkLjmGKZc5Md.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn5lChHrJaszJIyXnlgaz6Xg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn5lChHrJaszJIyXnlgaz6Xg.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn6Vrm09Vc8VRZOJbWhTIigd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn6Vrm09Vc8VRZOJbWhTIigd.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn7ZWNAdXvg4UZbLWqBJf2yh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn7ZWNAdXvg4UZbLWqBJf2yh.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcn8OMM3d3GRkIgwnHc1hSCjh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcn8OMM3d3GRkIgwnHc1hSCjh.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnADb2YDHqZm37TEACF98LtI.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnADb2YDHqZm37TEACF98LtI.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnAHohD8jQYdeMYJMdeuZxkc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnAHohD8jQYdeMYJMdeuZxkc.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnARhtVIowNIXDwo5QjFZnmh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnARhtVIowNIXDwo5QjFZnmh.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnC2Eg3D9X61sqbaJPB3Kp2f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnC2Eg3D9X61sqbaJPB3Kp2f.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnCiUW4Qo1p2Qc6hfXo96VAe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnCiUW4Qo1p2Qc6hfXo96VAe.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnFxR4HoSuuzrk6RYCVzCBOg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnFxR4HoSuuzrk6RYCVzCBOg.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnFyq7S9MamZsL36LGcOgOQe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnFyq7S9MamZsL36LGcOgOQe.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnGNXYmjel1Z2XoVRxK4kt6g.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnGNXYmjel1Z2XoVRxK4kt6g.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnHQ1vvmYL22k9uKq5rkKZFb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnHQ1vvmYL22k9uKq5rkKZFb.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnJg137wnmKcJ5BgDDnfgQ2n.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnJg137wnmKcJ5BgDDnfgQ2n.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnKwIOri3Lt1DmnoKDbxIoBd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnKwIOri3Lt1DmnoKDbxIoBd.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnPevppqdMDOuENHwQ39NLQ0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnPevppqdMDOuENHwQ39NLQ0.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnU4jh8M4Je3HH9hkrm8Ouvg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnU4jh8M4Je3HH9hkrm8Ouvg.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnYiBn8uesGTe4ZOmwXqhmOc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnYiBn8uesGTe4ZOmwXqhmOc.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnZd087QeiMwEXhESnXKsaGh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnZd087QeiMwEXhESnXKsaGh.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcna1WNPAzBk8jMDm7fgLDUah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcna1WNPAzBk8jMDm7fgLDUah.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcna7jKR0D2waFy8b1h1Mn9sh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcna7jKR0D2waFy8b1h1Mn9sh.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnfUN5uriCMTVxhTO3JUIgmf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnfUN5uriCMTVxhTO3JUIgmf.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcng4vXnqf40s8biMrNZJIyHg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcng4vXnqf40s8biMrNZJIyHg.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnhRvghde8oV88siXY6HEJdb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnhRvghde8oV88siXY6HEJdb.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnj0jnTpqsT2psX4PjN7RdUc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnj0jnTpqsT2psX4PjN7RdUc.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnkpN3TF5YXEVjpbgJ48gzQb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnkpN3TF5YXEVjpbgJ48gzQb.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnmheXItwGdTJR6YY3VCmWlb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnmheXItwGdTJR6YY3VCmWlb.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnn8lcAoQJkdADTdsktG3uhj.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnn8lcAoQJkdADTdsktG3uhj.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnni357jaooOc8dyVZgwOT0f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnni357jaooOc8dyVZgwOT0f.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnoEPle5mVh1MCEOAeCd78Kg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnoEPle5mVh1MCEOAeCd78Kg.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnoL6TtwSadFAq0JdJyQQ8Rg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnoL6TtwSadFAq0JdJyQQ8Rg.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnoVfyT94NXsCjur6xnLGEfb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnoVfyT94NXsCjur6xnLGEfb.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnqYLIQq0QByyf3UvEWc0jug.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnqYLIQq0QByyf3UvEWc0jug.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnunibrea2QMPlGTnUYyK9dh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnunibrea2QMPlGTnUYyK9dh.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnvy8YGoxrsZiEB3OuOtV76e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnvy8YGoxrsZiEB3OuOtV76e.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnwIP4hJADL0BfDkiO0EJcQ9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnwIP4hJADL0BfDkiO0EJcQ9.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnwl8p1SpMmjVjdDXcmQtRfd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnwl8p1SpMmjVjdDXcmQtRfd.jpg -------------------------------------------------------------------------------- /testdata/2/static/boxcnzb83lR9jSX5BQZlYIkvVac.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyroc/lark_docs_md/HEAD/testdata/2/static/boxcnzb83lR9jSX5BQZlYIkvVac.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | .idea/ 18 | ttt/ 19 | coverage.txt 20 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/chyroc/lark_docs_md 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/chyroc/lark v0.0.106 7 | github.com/stretchr/testify v1.8.1 8 | ) 9 | 10 | require ( 11 | github.com/chyroc/go-ptr v1.7.0 // indirect 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.1 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /.github/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | module_name=$(cat go.mod | grep module | cut -d ' ' -f 2-2) 6 | echo "module_name is $module_name" 7 | 8 | GO111MODULE=on echo 'mode: atomic' > coverage.txt && \ 9 | go list ./... | \ 10 | xargs -n1 -I{} sh -c 'LOCAL_TEST=true go test -covermode=atomic -coverprofile=coverage.tmp -coverpkg=./... -parallel 1 -p 1 -count=1 -gcflags=-l {} && tail -n +2 coverage.tmp >> coverage.txt' && \ 11 | rm coverage.tmp 12 | 13 | # go tool cover -func=coverage.txt -o coverage.txt 14 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | goreleaser: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - 13 | name: Checkout 14 | uses: actions/checkout@v2 15 | with: 16 | fetch-depth: 0 17 | - 18 | name: Set up Go 19 | uses: actions/setup-go@v2 20 | with: 21 | go-version: 1.16 22 | - 23 | name: Run GoReleaser 24 | uses: goreleaser/goreleaser-action@v2 25 | with: 26 | version: latest 27 | args: release --rm-dist 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # docs: http://goreleaser.com 2 | before: 3 | hooks: 4 | - go mod download 5 | builds: 6 | - env: 7 | - CGO_ENABLED=0 8 | goos: 9 | - linux 10 | - windows 11 | - darwin 12 | main: ./cmd/incr 13 | archives: 14 | - replacements: 15 | darwin: Darwin 16 | linux: Linux 17 | windows: Windows 18 | 386: i386 19 | amd64: x86_64 20 | checksum: 21 | name_template: 'checksums.txt' 22 | snapshot: 23 | name_template: "{{ .Tag }}-next" 24 | changelog: 25 | sort: asc 26 | filters: 27 | exclude: 28 | - '^docs:' 29 | - '^test:' 30 | source: 31 | enabled: true 32 | name_template: "{{.ProjectName}}-{{.Version}}" 33 | -------------------------------------------------------------------------------- /.github/workflows/codestyle-check.yml: -------------------------------------------------------------------------------- 1 | name: codestyle-check 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | schedule: 9 | - cron: "0 0 * * *" 10 | 11 | jobs: 12 | 13 | run: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: Set up Go 19 | uses: actions/setup-go@v2 20 | with: 21 | go-version: 1.17 22 | 23 | - name: Set up Check Tool 24 | run: | 25 | go get -u github.com/client9/misspell/cmd/misspell 26 | 27 | - name: Code Style Check 28 | run: | 29 | ls -alh 30 | go build -v ./... 31 | gofmt -s 32 | go vet ./... 33 | misspell -error -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: go-test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | run: 12 | runs-on: ubuntu-latest 13 | timeout-minutes: 30 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - name: Set up Go 18 | uses: actions/setup-go@v2 19 | with: 20 | go-version: 1.17 21 | 22 | - name: Build 23 | run: go build -v ./... 24 | 25 | - name: Test 26 | run: | 27 | export IN_CI=1 28 | ./.github/test.sh 29 | env: 30 | LARK_CHYROC_HEYMAN_APP_ID: ${{ secrets.LARK_CHYROC_HEYMAN_APP_ID }} 31 | LARK_CHYROC_HEYMAN_APP_SECRET: ${{ secrets.LARK_CHYROC_HEYMAN_APP_SECRET }} 32 | 33 | - name: Upload Cov 34 | run: bash <(curl -s https://codecov.io/bash) 35 | -------------------------------------------------------------------------------- /_examples/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/chyroc/lark" 8 | "github.com/chyroc/lark/larkext" 9 | "github.com/chyroc/lark_docs_md" 10 | ) 11 | 12 | func main() { 13 | larkClient := lark.New(lark.WithAppCredential("app-id", "app-secret")) 14 | docToken := "doc-token" 15 | 16 | // 这一步是获取 doc 内容 17 | doc, err := larkext.NewDoc(larkClient, docToken).Content(context.Background()) 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | // 转化为 markdown 23 | result := lark_docs_md.DocMarkdown(context.Background(), doc, &lark_docs_md.FormatOpt{ 24 | LarkClient: larkClient, 25 | 26 | // 如果需要下载图片等静态文件,请配置这两项 27 | // StaticDir: "static", 28 | // FilePrefix: "static", 29 | 30 | // 如果不需要下载文件,而替换为 24 小时有效的链接,请配置这个项 31 | StaticAsURL: true, 32 | }) 33 | 34 | // 输出 35 | fmt.Println(result) 36 | } 37 | -------------------------------------------------------------------------------- /static.go: -------------------------------------------------------------------------------- 1 | package lark_docs_md 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | "path/filepath" 10 | 11 | "github.com/chyroc/lark" 12 | ) 13 | 14 | func downloadFile(ctx context.Context, fileToken, name string, opt *FormatOpt) string { 15 | if opt.LarkClient == nil { 16 | return "" 17 | } 18 | if opt.StaticAsURL { 19 | resp, _, err := opt.LarkClient.Drive.BatchGetDriveMediaTmpDownloadURL(ctx, &lark.BatchGetDriveMediaTmpDownloadURLReq{ 20 | FileTokens: []string{fileToken}, 21 | }) 22 | if err != nil { 23 | log.Printf("lark get drive media tmp url %s fail: %s", fileToken, err) 24 | return "" 25 | } 26 | for _, v := range resp.TmpDownloadURLs { 27 | return v.TmpDownloadURL 28 | } 29 | return "" 30 | } else { 31 | resp, _, err := opt.LarkClient.Drive.DownloadDriveMedia(ctx, &lark.DownloadDriveMediaReq{ 32 | FileToken: fileToken, 33 | }) 34 | if err != nil { 35 | log.Printf("lark download drive media %s fail: %s", fileToken, err) 36 | return "" 37 | } 38 | filename := fmt.Sprintf("%s/%s", opt.StaticDir, name) 39 | mdname := fmt.Sprintf("%s/%s", opt.FilePrefix, name) 40 | _ = os.MkdirAll(filepath.Dir(filename), 0o755) 41 | f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, 0o666) 42 | if err != nil { 43 | log.Printf("open file %s fail: %s", filename, err) 44 | return "" 45 | } 46 | defer f.Close() 47 | 48 | _, _ = io.Copy(f, resp.File) 49 | return mdname 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/chyroc/go-ptr v1.7.0 h1:wwm53+SeMvpQbBcsZviNPlz2djpxyELjVOZFHtUjHho= 2 | github.com/chyroc/go-ptr v1.7.0/go.mod h1:+AAlVrPed1XbNyqZ7r/J3o79V1awCvd5wrYkxu8tsow= 3 | github.com/chyroc/lark v0.0.106 h1:zU3bCqDROLU5t25SJKCBXY8tDZE+ANAElZhokC7jDOQ= 4 | github.com/chyroc/lark v0.0.106/go.mod h1:iYv0NXuCzYeypk1eY9Mos6QP7CQuLK7YH3Oxi09p7NU= 5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 9 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 10 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 11 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 12 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 13 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 14 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 15 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 16 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 17 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 18 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 19 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 20 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 21 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lark_docs_md 2 | 3 | [![codecov](https://codecov.io/gh/chyroc/lark_docs_md/branch/master/graph/badge.svg?token=Z73T6YFF80)](https://codecov.io/gh/chyroc/lark_docs_md) 4 | [![go report card](https://goreportcard.com/badge/github.com/chyroc/lark_docs_md "go report card")](https://goreportcard.com/report/github.com/chyroc/lark_docs_md) 5 | [![test status](https://github.com/chyroc/lark_docs_md/actions/workflows/test.yml/badge.svg)](https://github.com/chyroc/lark_docs_md/actions) 6 | [![Apache-2.0 license](https://img.shields.io/badge/License-Apache%202.0-brightgreen.svg)](https://opensource.org/licenses/Apache-2.0) 7 | [![Go.Dev reference](https://img.shields.io/badge/go.dev-reference-blue?logo=go&logoColor=white)](https://pkg.go.dev/github.com/chyroc/lark_docs_md) 8 | [![Go project version](https://badge.fury.io/go/github.com%2Fchyroc%2Flark_docs_md.svg)](https://badge.fury.io/go/github.com%2Fchyroc%2Flark_docs_md) 9 | 10 | ![](./header.png) 11 | 12 | ## Install 13 | 14 | ```shell 15 | go get github.com/chyroc/lark_docs_md 16 | ``` 17 | 18 | ## Usage 19 | 20 | ```go 21 | package main 22 | 23 | import ( 24 | "context" 25 | "fmt" 26 | 27 | "github.com/chyroc/lark" 28 | "github.com/chyroc/lark/larkext" 29 | "github.com/chyroc/lark_docs_md" 30 | ) 31 | 32 | func main() { 33 | larkClient := lark.New(lark.WithAppCredential("app-id", "app-secret")) 34 | docToken := "doc-token" 35 | 36 | // 这一步是获取 doc 内容 37 | doc, err := larkext.NewDoc(larkClient, docToken).Content(context.Background()) 38 | if err != nil { 39 | panic(err) 40 | } 41 | 42 | // 转化为 markdown 43 | result := lark_docs_md.DocMarkdown(context.Background(), doc, &lark_docs_md.FormatOpt{ 44 | LarkClient: larkClient, 45 | 46 | // 如果需要下载图片等静态文件,请配置这两项 47 | // StaticDir: "static", 48 | // FilePrefix: "static", 49 | 50 | // 如果不需要下载文件,而替换为 24 小时有效的链接,请配置这个项 51 | StaticAsURL: true, 52 | }) 53 | 54 | // 输出 55 | fmt.Println(result) 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /testdata/1/data.md: -------------------------------------------------------------------------------- 1 | # 📔 这是一个飞书文档的例子 2 | 3 | > 这是一个飞书文档的例子,包含所有 Markdown 支持的语法 4 | 5 | # 标题 6 | 7 | ## 二级标题 8 | 9 | ### 三级标题 10 | 11 | #### 四级标题 12 | 13 | ##### 五级标题 14 | 15 | ###### 六级标题 16 | 17 | # 正文 18 | 19 | 正文,这是正文,这个是正文,这个是正文啊。 20 | 正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。 21 | # 列表 22 | 23 | ## 有序列表 24 | 25 | 1. 1 26 | 1. A 27 | 1. i 28 | 1. 1 29 | 1. a 30 | 2. b 31 | 3. X 32 | 2. 2 33 | 3. 3 34 | 2. Ii 35 | 3. Iii 36 | 4. iv 37 | 5. Dd 38 | 2. B 39 | 3. C 40 | 4. D 41 | 5. E 42 | 6. F 43 | 7. G 44 | 2. 2 45 | 3. 3 46 | ## 无序列表 47 | 48 | - X 49 | - XX 50 | - XXX 51 | - XXX 52 | - XXXX 53 | - X 54 | - X 55 | # 任务列表 56 | 57 | - [ ] 任务 x 58 | - [ ] 任务 xx 59 | - [ ] 任务 x 60 | - [x] 完成的任务 x 61 | # 高亮块 62 | 63 | ``` 64 | 高亮块 65 | 66 | 高亮块支持颜色,转成 Markdown 后不支持 67 | 68 | ``` 69 | # 分割线 70 | 71 | 72 | --- 73 | 74 | # 引用 75 | 76 | > 这是一个引用 77 | 78 | > 这是一个引用,有 tab 79 | 80 | > 引用行 1 81 | > 引用行 2 82 | > 引用行 3 83 | 84 | # 代码块 85 | 86 | ```Go 87 | func f() { 88 | // do sth 89 | } 90 | 91 | ``` 92 | # 图片 93 | 94 | ## 一个图片 95 | 96 | 97 | ## 并排图片 98 | 99 | 100 | 101 | # 表格 102 | 103 | 104 | # 电子表格 105 | 106 | `[sheet: shtcnVZBJ1F05uW16LwcibZDJdf_8OPm5F]` 107 | # 链接 108 | 109 | [链接文本](https%3A%2F%2Fply.readthedocs.io%2Fen%2Flatest%2Fply.html) 110 | # 网页卡片 111 | 112 | `[undefined-block]` 113 | # 云文档 114 | 115 | [云文档](https://rs6qnacjws.feishu.cn/docs/doccnKOgFFoPz5Z1OZ5wU9H7sdf) 116 | # 群名片 117 | 118 | `[chat: oc_e5dc4d726035aff7317c168440ed5b5b]` 119 | # 文件 120 | 121 | [file: pending.png](static/pending.png) 122 | 123 | -------------------------------------------------------------------------------- /md_test.go: -------------------------------------------------------------------------------- 1 | package lark_docs_md_test 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "os" 9 | "testing" 10 | "time" 11 | 12 | "github.com/chyroc/lark" 13 | "github.com/chyroc/lark/larkext" 14 | "github.com/chyroc/lark_docs_md" 15 | "github.com/stretchr/testify/assert" 16 | ) 17 | 18 | func TestDocMarkdown(t *testing.T) { 19 | as := assert.New(t) 20 | larkClient := lark.New( 21 | lark.WithAppCredential(os.Getenv("LARK_CHYROC_HEYMAN_APP_ID"), os.Getenv("LARK_CHYROC_HEYMAN_APP_SECRET")), 22 | lark.WithTimeout(time.Minute), 23 | ) 24 | 25 | tests := []struct { 26 | name string 27 | }{ 28 | {"1"}, 29 | {"2"}, 30 | } 31 | for _, tt := range tests { 32 | t.Run(tt.name, func(t *testing.T) { 33 | opt := &lark_docs_md.FormatOpt{ 34 | LarkClient: larkClient, 35 | StaticDir: fmt.Sprintf("testdata/%s/static", tt.name), 36 | FilePrefix: "static", 37 | } 38 | 39 | doc := loadDocContent(t, tt.name) 40 | md := loadMarkdown(t, tt.name) 41 | result := lark_docs_md.DocMarkdown(context.Background(), doc, opt) 42 | as.Equal(md, result, tt.name) 43 | }) 44 | } 45 | } 46 | 47 | func Test_FromDocToken(t *testing.T) { 48 | t.Skip() 49 | 50 | as := assert.New(t) 51 | 52 | // https://rs6qnacjws.feishu.cn/docs/doccng7C51ULsOrHtbmWBa3a4Hf 53 | larkClient := lark.New( 54 | lark.WithAppCredential(os.Getenv("LARK_CHYROC_HEYMAN_APP_ID"), os.Getenv("LARK_CHYROC_HEYMAN_APP_SECRET")), 55 | ) 56 | docToken := "doccng7C51ULsOrHtbmWBa3a4Hf" 57 | 58 | doc, err := larkext.NewDoc(larkClient, docToken).Content(context.Background()) 59 | as.Nil(err) 60 | 61 | result := lark_docs_md.DocMarkdown(context.Background(), doc, &lark_docs_md.FormatOpt{ 62 | LarkClient: larkClient, 63 | // StaticDir: "/tmp/tmp-static", 64 | // FilePrefix: "static", 65 | StaticAsURL: true, 66 | }) 67 | fmt.Println(result) 68 | } 69 | 70 | func loadDocContent(t *testing.T, testCase string) *lark.DocContent { 71 | as := assert.New(t) 72 | 73 | bs, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s/data.json", testCase)) 74 | as.Nil(err) 75 | 76 | doc := &lark.DocContent{} 77 | as.Nil(json.Unmarshal(bs, doc)) 78 | 79 | return doc 80 | } 81 | 82 | func loadMarkdown(t *testing.T, testCase string) string { 83 | as := assert.New(t) 84 | 85 | bs, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s/data.md", testCase)) 86 | as.Nil(err) 87 | 88 | return string(bs) 89 | } 90 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "codeql-analtsis" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '39 15 * * 6' 22 | 23 | jobs: 24 | run: 25 | runs-on: ubuntu-latest 26 | permissions: 27 | actions: read 28 | contents: read 29 | security-events: write 30 | 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | language: [ 'go' ] 35 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 36 | # Learn more: 37 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v1 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v1 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v1 71 | -------------------------------------------------------------------------------- /md.go: -------------------------------------------------------------------------------- 1 | package lark_docs_md 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "strings" 7 | 8 | "github.com/chyroc/lark" 9 | ) 10 | 11 | type FormatOpt struct { 12 | ctx context.Context 13 | LarkClient *lark.Lark // lark 客户端 14 | StaticDir string // 如果需要下载静态文件,那么需要指定静态文件的目录 15 | FilePrefix string // 针对静态文件,需要指定文件在 Markdown 中的前缀 16 | StaticAsURL bool // 不下载静态文件,直接把静态文件的 URL 插入到 Markdown 中 17 | } 18 | 19 | func DocMarkdown(ctx context.Context, doc *lark.DocContent, opt *FormatOpt) string { 20 | if opt == nil { 21 | opt = new(FormatOpt) 22 | } 23 | opt.ctx = ctx 24 | if opt.StaticDir == "" { 25 | opt.StaticDir = "static" 26 | } 27 | if opt.FilePrefix == "" { 28 | opt.FilePrefix = "static" 29 | } 30 | 31 | buf := new(strings.Builder) 32 | 33 | buf.WriteString("# ") 34 | buf.WriteString(DocParagraphMarkdown(doc.Title, opt)) 35 | buf.WriteString("\n\n") 36 | 37 | buf.WriteString(DocBodyMarkdown(doc.Body, opt)) 38 | 39 | return buf.String() 40 | } 41 | 42 | func DocBodyMarkdown(r *lark.DocBody, opt *FormatOpt) string { 43 | buf := new(strings.Builder) 44 | 45 | for idx, v := range r.Blocks { 46 | buf.WriteString(DocBlockMarkdown(v, opt)) 47 | buf.WriteString("\n") 48 | 49 | // 如果 v 是 list,并且是最后一个,那么需要换行 50 | if idx == len(r.Blocks)-1 && v.Type == lark.DocBlockTypeParagraph && v.Paragraph.Style != nil && v.Paragraph.Style.List != nil && v.Paragraph.Style.List.IndentLevel > 0 { 51 | buf.WriteString("\n") 52 | } 53 | } 54 | 55 | return buf.String() 56 | } 57 | 58 | func DocBlockMarkdown(r *lark.DocBlock, opt *FormatOpt) string { 59 | switch r.Type { 60 | case "paragraph": 61 | return DocParagraphMarkdown(r.Paragraph, opt) 62 | case "gallery": 63 | return DocGalleryMarkdown(r.Gallery, opt) 64 | case "file": 65 | return DocFileMarkdown(r.File, opt) 66 | case "chatGroup": 67 | return DocChatGroupMarkdown(r.ChatGroup, opt) 68 | case "table": 69 | return DocTableMarkdown(r.Table, opt) 70 | case "horizontalLine": 71 | return DocHorizontalLineMarkdown(r.HorizontalLine, opt) 72 | case "embeddedPage": 73 | return DocEmbeddedPageMarkdown(r.EmbeddedPage, opt) 74 | case "sheet": 75 | return DocSheetMarkdown(r.Sheet, opt) 76 | case "bitable": 77 | return DocBitableMarkdown(r.Bitable, opt) 78 | case "diagram": 79 | return DocDiagramMarkdown(r.Diagram, opt) 80 | case "jira": 81 | return DocJiraMarkdown(r.Jira, opt) 82 | case "poll": 83 | return DocPollMarkdown(r.Poll, opt) 84 | case "code": 85 | return DocCodeMarkdown(r.Code, opt) 86 | case "docsApp": 87 | return DocDocsAppMarkdown(r.DocsApp, opt) 88 | case "callout": 89 | return DocCalloutMarkdown(r.Callout, opt) 90 | case "undefinedBlock": 91 | return DocUndefinedBlockMarkdown(r.UndefinedBlock, opt) 92 | default: 93 | return fmt.Sprintf("", r.Type) 94 | } 95 | } 96 | 97 | func DocParagraphMarkdown(r *lark.DocParagraph, opt *FormatOpt) string { 98 | buf := new(strings.Builder) 99 | 100 | if r.Style != nil { 101 | if r.Style.HeadingLevel > 0 { 102 | buf.WriteString(strings.Repeat("#", int(r.Style.HeadingLevel))) 103 | buf.WriteString(" ") 104 | } 105 | if r.Style.List != nil { 106 | buf.WriteString(r.Style.List.ListTag()) 107 | buf.WriteString(" ") 108 | } 109 | switch { 110 | case r.Style.Quote: 111 | buf.WriteString("> ") 112 | } 113 | } 114 | 115 | for _, v := range r.Elements { 116 | buf.WriteString(DocParagraphElementMarkdown(v, opt)) 117 | } 118 | 119 | if r.Style != nil { 120 | if r.Style.List != nil && r.Style.List.IndentLevel > 0 { 121 | // 122 | } else { 123 | buf.WriteString("\n") 124 | } 125 | } 126 | 127 | return buf.String() 128 | } 129 | 130 | func DocGalleryMarkdown(r *lark.DocGallery, opt *FormatOpt) string { 131 | buf := new(strings.Builder) 132 | 133 | for _, v := range r.ImageList { 134 | buf.WriteString(DocImageItemMarkdown(v, opt)) 135 | } 136 | 137 | return buf.String() 138 | } 139 | 140 | func DocImageItemMarkdown(r *lark.DocImageItem, opt *FormatOpt) string { 141 | if opt.LarkClient == nil { 142 | return fmt.Sprintf("`[image: %s]`", r.FileToken) 143 | } 144 | 145 | target := downloadFile(opt.ctx, r.FileToken, r.FileToken+".jpg", opt) 146 | return fmt.Sprintf("", target, r.Width, r.Height) 147 | } 148 | 149 | func DocChatGroupMarkdown(r *lark.DocChatGroup, opt *FormatOpt) string { 150 | return fmt.Sprintf("`[chat: %s]`", r.OpenChatID) 151 | } 152 | 153 | func DocTableMarkdown(r *lark.DocTable, opt *FormatOpt) string { 154 | // todo 155 | buf := new(strings.Builder) 156 | 157 | return buf.String() 158 | } 159 | 160 | func DocHorizontalLineMarkdown(r *lark.DocHorizontalLine, opt *FormatOpt) string { 161 | return "\n---\n" 162 | } 163 | 164 | func DocEmbeddedPageMarkdown(r *lark.DocEmbeddedPage, opt *FormatOpt) string { 165 | return fmt.Sprintf("[embedded-page: %s](%s)", r.Type, r.Url) 166 | } 167 | 168 | func DocSheetMarkdown(r *lark.DocSheet, opt *FormatOpt) string { 169 | return fmt.Sprintf("`[sheet: %s]`", r.Token) 170 | } 171 | 172 | func DocBitableMarkdown(r *lark.DocBitable, opt *FormatOpt) string { 173 | return fmt.Sprintf("`[bitable: %s / %s]`", r.ViewType, r.Token) 174 | } 175 | 176 | func DocDiagramMarkdown(r *lark.DocDiagram, opt *FormatOpt) string { 177 | return fmt.Sprintf("`[diagram: %s / %s]`", r.DiagramType, r.Token) 178 | } 179 | 180 | func DocPollMarkdown(r *lark.DocPoll, opt *FormatOpt) string { 181 | return fmt.Sprintf("`[poll: %s]`", r.Token) 182 | } 183 | 184 | func DocCodeMarkdown(r *lark.DocCode, opt *FormatOpt) string { 185 | buf := new(strings.Builder) 186 | 187 | buf.WriteString("```") 188 | if r.Language != "" { 189 | buf.WriteString(r.Language) 190 | } 191 | buf.WriteString("\n") 192 | 193 | buf.WriteString(DocBodyMarkdown(r.Body, opt)) 194 | 195 | buf.WriteString("\n") 196 | buf.WriteString("```") 197 | 198 | return buf.String() 199 | } 200 | 201 | func DocDocsAppMarkdown(r *lark.DocDocsApp, opt *FormatOpt) string { 202 | return fmt.Sprintf("`[docs-app: %s]`", r.TypeID) 203 | } 204 | 205 | func DocCalloutMarkdown(r *lark.DocCallout, opt *FormatOpt) string { 206 | buf := new(strings.Builder) 207 | 208 | buf.WriteString("```") 209 | buf.WriteString("\n") 210 | 211 | buf.WriteString(DocBodyMarkdown(r.Body, opt)) 212 | 213 | buf.WriteString("\n") 214 | buf.WriteString("```") 215 | 216 | return buf.String() 217 | } 218 | 219 | func DocUndefinedBlockMarkdown(r *lark.DocUndefinedBlock, opt *FormatOpt) string { 220 | return "`[undefined-block]`" 221 | } 222 | 223 | func DocParagraphElementMarkdown(r *lark.DocParagraphElement, opt *FormatOpt) string { 224 | switch r.Type { 225 | case "textRun": 226 | return DocTextRunMarkdown(r.TextRun, opt) 227 | case "docsLink": 228 | return DocDocsLinkMarkdown(r.DocsLink, opt) 229 | case "person": 230 | return DocPersonMarkdown(r.Person, opt) 231 | case "equation": 232 | return DocEquationMarkdown(r.Equation, opt) 233 | case "reminder": 234 | return DocReminderMarkdown(r.Reminder, opt) 235 | case "file": 236 | return DocFileMarkdown(r.File, opt) 237 | case "jira": 238 | return DocJiraMarkdown(r.Jira, opt) 239 | case "undefinedElement": 240 | return DocUndefinedElementMarkdown(r.UndefinedElement, opt) 241 | default: 242 | return fmt.Sprintf("", r.Type) 243 | } 244 | } 245 | 246 | func DocTextRunMarkdown(r *lark.DocTextRun, opt *FormatOpt) string { 247 | // **加粗** 248 | // _斜体_ 249 | // ~~删除线~~ 250 | // 下划线 251 | // `行内代码` 252 | // [title](url) 253 | buf := new(strings.Builder) 254 | if r.Style != nil { 255 | switch { 256 | case r.Style.Bold: 257 | buf.WriteString("**") 258 | case r.Style.Italic: 259 | buf.WriteString("_") 260 | case r.Style.StrikeThrough: 261 | buf.WriteString("~~") 262 | case r.Style.Underline: 263 | buf.WriteString("") 264 | case r.Style.CodeInline: 265 | buf.WriteString("`") 266 | case r.Style.Link != nil && r.Style.Link.URL != "": 267 | buf.WriteString("[") 268 | } 269 | } 270 | 271 | buf.WriteString(r.Text) 272 | 273 | if r.Style != nil { 274 | switch { 275 | case r.Style.Bold: 276 | buf.WriteString("**") 277 | case r.Style.Italic: 278 | buf.WriteString("_") 279 | case r.Style.StrikeThrough: 280 | buf.WriteString("~~") 281 | case r.Style.Underline: 282 | buf.WriteString("") 283 | case r.Style.CodeInline: 284 | buf.WriteString("`") 285 | case r.Style.Link != nil && r.Style.Link.URL != "": 286 | buf.WriteString("](") 287 | buf.WriteString(r.Style.Link.URL) 288 | buf.WriteString(")") 289 | } 290 | } 291 | 292 | return buf.String() 293 | } 294 | 295 | func DocDocsLinkMarkdown(r *lark.DocDocsLink, opt *FormatOpt) string { 296 | return fmt.Sprintf("[%s](%s)", "云文档", r.URL) 297 | } 298 | 299 | func DocPersonMarkdown(r *lark.DocPerson, opt *FormatOpt) string { 300 | return "@" + r.OpenID 301 | } 302 | 303 | func DocEquationMarkdown(r *lark.DocEquation, opt *FormatOpt) string { 304 | return fmt.Sprintf("$$%s$$", r.Equation) 305 | } 306 | 307 | func DocReminderMarkdown(r *lark.DocReminder, opt *FormatOpt) string { 308 | return "`[doc-reminder]`" 309 | } 310 | 311 | func DocFileMarkdown(r *lark.DocFile, opt *FormatOpt) string { 312 | if opt.LarkClient == nil { 313 | return fmt.Sprintf("`[file: %s / %s]`", r.FileName, r.FileToken) 314 | } 315 | 316 | target := downloadFile(opt.ctx, r.FileToken, r.FileName, opt) 317 | return fmt.Sprintf("[file: %s](%s)", r.FileName, target) 318 | } 319 | 320 | func DocJiraMarkdown(r *lark.DocJira, opt *FormatOpt) string { 321 | return fmt.Sprintf("`[jira: %s / %s]`", r.JiraType, r.Token) 322 | } 323 | 324 | func DocUndefinedElementMarkdown(r *lark.DocUndefinedElement, opt *FormatOpt) string { 325 | return "`[undefined-element]`" 326 | } 327 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /testdata/2/data.md: -------------------------------------------------------------------------------- 1 | # Lark SDK Ext 使用指南 2 | 3 | > Lark SDK 项目:https://github.com/chyroc/lark 4 | > Lark SDK Ext 是在 Lark SDK 上层,面向 Drive/Sheet/Doc 等操作封装的一层方法 5 | > 注意:下面所有的 ctx 都是指在一次请求过程的上下文,是标准库 `context.Context` 的实例 6 | 7 | # 一些例子 8 | 9 | - 将图片马赛克化,并填充到 Sheet:https://github.com/chyroc/draw-lark-sheet 10 | # 初始化 Lark 客户端 11 | 12 | ```Go 13 | package main 14 | 15 | import ( 16 | "github.com/chyroc/lark" 17 | ) 18 | 19 | func main() { 20 | larkClient := lark.New( 21 | lark.WithAppCredential(r.AppID, r.AppSecret) 22 | ) 23 | } 24 | 25 | ``` 26 | > 注意:下面所有的 `larkCli` 都是指的 Lark SDK 客户端 27 | # Folder / 文件夹 28 | 29 | ## 创建我的空间跟目录 Folder Client 30 | 31 | ```Go 32 | package main 33 | 34 | import ( 35 | "context" 36 | 37 | "github.com/chyroc/lark" 38 | "github.com/chyroc/lark/larkext" 39 | ) 40 | 41 | func example(ctx context.Context, larkClient *lark.Lark) { 42 | folderRootClient, err := larkext.NewRootFolder(ctx, r) 43 | if err != nil { 44 | panic(err) 45 | } 46 | 47 | _ = folderRootClient 48 | } 49 | 50 | ``` 51 | ## 从已有的 Folder Token 创建 Folder Client 52 | 53 | ```Go 54 | package main 55 | 56 | import ( 57 | "context" 58 | 59 | "github.com/chyroc/lark" 60 | "github.com/chyroc/lark/larkext" 61 | ) 62 | 63 | func example(ctx context.Context, larkClient *lark.Lark, folderToken string) { 64 | folderClient := larkext.NewFolder(larkClient, folderToken) 65 | } 66 | 67 | ``` 68 | > 注意:下面提到的 `folderClient` 都是指这样创建的 Folder Client 69 | 70 | ## 获取文件夹的元信息 71 | 72 | ```Go 73 | package main 74 | 75 | import ( 76 | "context" 77 | 78 | "github.com/chyroc/lark/larkext" 79 | ) 80 | 81 | func example(ctx context.Context, folderClient *larkext.Folder) { 82 | meta, err := folderClient.Meta(ctx) 83 | if err != nil { 84 | panic(err) 85 | } 86 | 87 | _ = meta 88 | } 89 | 90 | ``` 91 | ## 列出一个文件下的文件列表 92 | 93 | ```Go 94 | package main 95 | 96 | import ( 97 | "context" 98 | 99 | "github.com/chyroc/lark/larkext" 100 | ) 101 | 102 | func example(ctx context.Context, folderClient *larkext.Folder) { 103 | files, err := folderClient.ListFiles(ctx) 104 | if err != nil { 105 | panic(err) 106 | } 107 | 108 | _ = files 109 | } 110 | 111 | ``` 112 | ## 在文件夹内创建文件夹 113 | 114 | ```Go 115 | package main 116 | 117 | import ( 118 | "context" 119 | 120 | "github.com/chyroc/lark/larkext" 121 | ) 122 | 123 | func example(ctx context.Context, folderClient *larkext.Folder) { 124 | childFolderClient, err := folderClient.NewFolder(ctx, "child") 125 | if err != nil { 126 | panic(err) 127 | } 128 | 129 | _ = childFolderClient 130 | } 131 | 132 | ``` 133 | ## 在文件夹内创建文档 Doc 134 | 135 | ```Go 136 | package main 137 | 138 | import ( 139 | "context" 140 | 141 | "github.com/chyroc/lark/larkext" 142 | ) 143 | 144 | func example(ctx context.Context, folderClient *larkext.Folder) { 145 | docClient, err := folderClient.NewDoc(ctx, "doc title") 146 | if err != nil { 147 | panic(err) 148 | } 149 | 150 | _ = docClient 151 | } 152 | 153 | ``` 154 | ## 在文件夹内创建表格 Sheet 155 | 156 | ```Go 157 | package main 158 | 159 | import ( 160 | "context" 161 | 162 | "github.com/chyroc/lark/larkext" 163 | ) 164 | 165 | func example(ctx context.Context, folderClient *larkext.Folder) { 166 | sheetClient, err := folderClient.NewSheet(ctx, "sheet title") 167 | if err != nil { 168 | panic(err) 169 | } 170 | 171 | _ = sheetClient 172 | } 173 | 174 | ``` 175 | ## 删除文档 176 | 177 | ```Go 178 | package main 179 | 180 | import ( 181 | "context" 182 | 183 | "github.com/chyroc/lark/larkext" 184 | ) 185 | 186 | func example(ctx context.Context, folderClient *larkext.Folder) { 187 | err := folderClient.DeleteDoc(ctx, "doc-token") 188 | if err != nil { 189 | panic(err) 190 | } 191 | } 192 | 193 | ``` 194 | ## 删除表格 195 | 196 | ```Go 197 | package main 198 | 199 | import ( 200 | "context" 201 | 202 | "github.com/chyroc/lark/larkext" 203 | ) 204 | 205 | func example(ctx context.Context, folderClient *larkext.Folder) { 206 | err := folderClient.DeleteSheet(ctx, "sheet-token") 207 | if err != nil { 208 | panic(err) 209 | } 210 | } 211 | 212 | ``` 213 | # Sheet / 电子表格 214 | 215 | ## Sheet 使用前说明 216 | 217 | ### 表格坐标、索引 218 | 219 | 表格以左上角第一个单元格作为原点,坐标是:`(1, 1)`,体现为 Sheet 坐标就是:`A1`。 220 | 横向是 X 轴,从左往右增加;纵向是 Y 轴,从上往下增加。 221 | 222 | ### 将横坐标 X 轴,从数字转成 `A` `Z` `AZ` 等格式 223 | 224 | ```Go 225 | package main 226 | 227 | import ( 228 | "github.com/chyroc/lark/larkext" 229 | ) 230 | 231 | func exampled() { 232 | larkext.ItoCol(1) _// A_ 233 | _ _larkext.ItoCol(26) _// Z_ 234 | _ _larkext.ItoCol(27) _// AA_ 235 | } 236 | 237 | ``` 238 | 将单元格范围 `(x1, y1) , (x2, y2)` 转成 `sheet!A1:D3` 格式 239 | ```Go 240 | package main 241 | 242 | import ( 243 | "github.com/chyroc/lark/larkext" 244 | ) 245 | 246 | func exampled() { 247 | larkext.CellRange("sheet1", 1, 1, 2, 2) _// sheet1!A1:B2_ 248 | _ _larkext.CellRange("sheet1", 1, 100, 26, 200) _// sheet1!A100:Z200_ 249 | } 250 | 251 | ``` 252 | ## 从已有的 Sheet 创建 Sheet 客户端 253 | 254 | ```Go 255 | package main 256 | 257 | import ( 258 | "context" 259 | 260 | "github.com/chyroc/lark" 261 | "github.com/chyroc/lark/larkext" 262 | ) 263 | 264 | func example(ctx context.Context, larkClient *lark.Lark, sheetToken string) { 265 | sheetClient := larkext.NewSheet(larkClient, sheetToken) 266 | 267 | _ = sheetClient 268 | } 269 | 270 | ``` 271 | > 注意:下面所有的 `sheetClient` 都是指 larkext.Sheet 实例 272 | 273 | ## 创建新的 Sheet,并创建它的客户端 274 | 275 | ```Go 276 | package main 277 | 278 | import ( 279 | "context" 280 | 281 | "github.com/chyroc/lark/larkext" 282 | ) 283 | 284 | func example(ctx context.Context, folderClient *larkext.Folder) { 285 | sheetClient, err := folderClient.NewSheet(ctx, "sheet title") 286 | if err != nil { 287 | panic(err) 288 | } 289 | 290 | _ = sheetClient 291 | } 292 | 293 | ``` 294 | 295 | ## 获取 Sheet 元数据 296 | 297 | ```Go 298 | package main 299 | 300 | import ( 301 | "context" 302 | 303 | "github.com/chyroc/lark/larkext" 304 | "github.com/davecgh/go-spew/spew" 305 | ) 306 | 307 | func example(ctx context.Context, sheetIns *larkext.Sheet) { 308 | meta, err := sheetIns.Meta(ctx) 309 | if err != nil { 310 | panic(err) 311 | } 312 | spew.Dump(meta) 313 | } 314 | 315 | ``` 316 | ## 获取 Sheet 数据 317 | 318 | ```Go 319 | package main 320 | 321 | import ( 322 | "context" 323 | "fmt" 324 | 325 | "github.com/chyroc/lark" 326 | "github.com/chyroc/lark/larkext" 327 | ) 328 | 329 | func example(ctx context.Context, sheetIns *larkext.Sheet) { 330 | cellRange := larkext.CellRange("sheet-id", 1, 1, 10, 10) 331 | resp, err := sheetIns.Get(ctx, cellRange, &lark.GetSheetValueReq{}) 332 | if err != nil { 333 | panic(err) 334 | } 335 | for _, vv := range resp.ValueRange.Values { 336 | for _, v := range vv { 337 | switch v.Type() { 338 | case lark.SheetContentTypeString: 339 | fmt.Println(*v.String) 340 | case lark.SheetContentTypeInt: 341 | fmt.Println(*v.Int) 342 | } 343 | } 344 | } 345 | } 346 | 347 | ``` 348 | ## 删除 Sheet 自己 349 | 350 | ```Go 351 | package main 352 | 353 | import ( 354 | "context" 355 | 356 | "github.com/chyroc/lark/larkext" 357 | ) 358 | 359 | func example(ctx context.Context, sheetIns *larkext.Sheet) { 360 | err := sheetIns.Delete(ctx) 361 | if err != nil { 362 | panic(err) 363 | } 364 | } 365 | 366 | ``` 367 | 368 | 369 | ## 设置 Sheet 标题 370 | 371 | ```Go 372 | package test 373 | 374 | import ( 375 | "context" 376 | 377 | "github.com/chyroc/lark/larkext" 378 | ) 379 | 380 | func example(ctx context.Context, sheetIns *larkext.Sheet) { 381 | sheetIns.SetTitle(ctx, "this is title") 382 | } 383 | 384 | ``` 385 | 386 | ## 设置工作表标题 387 | 388 | ```Go 389 | package main 390 | 391 | import ( 392 | "context" 393 | 394 | "github.com/chyroc/lark/larkext" 395 | ) 396 | 397 | func example(ctx context.Context, sheetClient *larkext.Sheet) { 398 | err := sheetClient.SetSheetTitle(ctx, "sheet-id", "sheet title") 399 | if err != nil { 400 | panic(err) 401 | } 402 | } 403 | 404 | ``` 405 | 406 | ## 设置工作表位置 407 | 408 | ```Go 409 | package main 410 | 411 | import ( 412 | "context" 413 | 414 | "github.com/chyroc/lark/larkext" 415 | ) 416 | 417 | func example(ctx context.Context, sheetClient *larkext.Sheet) { 418 | err := sheetClient.SetSheetIndex(ctx, "sheet-id", 1) 419 | if err != nil { 420 | panic(err) 421 | } 422 | } 423 | 424 | ``` 425 | ## 隐藏工作表 426 | 427 | ```Go 428 | package main 429 | 430 | import ( 431 | "context" 432 | 433 | "github.com/chyroc/lark/larkext" 434 | ) 435 | 436 | func example(ctx context.Context, sheetClient *larkext.Sheet) { 437 | err := sheetClient.HideSheet(ctx, "sheet-id", true) 438 | if err != nil { 439 | panic(err) 440 | } 441 | } 442 | 443 | ``` 444 | 445 | ## 冻结行与列 446 | 447 | ```Go 448 | package main 449 | 450 | import ( 451 | "context" 452 | 453 | "github.com/chyroc/lark/larkext" 454 | ) 455 | 456 | func example(ctx context.Context, sheetClient *larkext.Sheet) { 457 | _// 冻结 1-2 行,1-3(A-C) 列_ 458 | _ _{ 459 | err := sheetClient.FrozenSheet(ctx, "sheet-id", 2, 3) 460 | if err != nil { 461 | panic(err) 462 | } 463 | } 464 | 465 | _// 取消冻结_ 466 | _ _{ 467 | err := sheetClient.FrozenSheet(ctx, "sheet-id", 0,0) 468 | if err != nil { 469 | panic(err) 470 | } 471 | } 472 | } 473 | 474 | ``` 475 | ## 锁定工作表 476 | 477 | ```Go 478 | package main 479 | 480 | import ( 481 | "context" 482 | 483 | "github.com/chyroc/lark/larkext" 484 | ) 485 | 486 | func example(ctx context.Context, sheetClient *larkext.Sheet) { 487 | err := sheetClient.LockSheet(ctx, "sheet-id", "lock-info", nil) 488 | if err != nil { 489 | panic(err) 490 | } 491 | } 492 | 493 | ``` 494 | 495 | ## 解锁工作表 496 | 497 | ```Go 498 | package main 499 | 500 | import ( 501 | "context" 502 | 503 | "github.com/chyroc/lark/larkext" 504 | ) 505 | 506 | func example(ctx context.Context, sheetClient *larkext.Sheet) { 507 | err := sheetClient.UnlockSheet(ctx, "sheet-id") 508 | if err != nil { 509 | panic(err) 510 | } 511 | } 512 | 513 | ``` 514 | ## 移动行数据 515 | 516 | ```Go 517 | package main 518 | 519 | import ( 520 | "context" 521 | 522 | "github.com/chyroc/lark" 523 | "github.com/chyroc/lark/larkext" 524 | ) 525 | 526 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 527 | _ = sheetClient.MoveRows(ctx, sheetID, 3, 2, -1) 528 | } 529 | 530 | ``` 531 | > 将第 3 行开始,连续 2 行的数据,向上(负号表示上)移动 1 行 532 | > 上面的数据会被积压下来 533 | 534 | 535 | ## 移动列数据 536 | 537 | ```Go 538 | package main 539 | 540 | import ( 541 | "context" 542 | 543 | "github.com/chyroc/lark" 544 | "github.com/chyroc/lark/larkext" 545 | ) 546 | 547 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 548 | _ = sheetClient.MoveCols(ctx, sheetID, 3, 2, -2) 549 | } 550 | 551 | ``` 552 | > 将第 3 列开始,连续 2 列的数据,向左(负号 表示左)移动 2 列 553 | > 左边的数据会被挤压到右边 554 | 555 | ## 插入行数据 556 | 557 | ```Go 558 | package main 559 | 560 | import ( 561 | "context" 562 | 563 | "github.com/chyroc/lark" 564 | "github.com/chyroc/lark/larkext" 565 | ) 566 | 567 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 568 | _ = sheetClient.InsertRows(ctx, sheetID, 3, 2) 569 | } 570 | 571 | ``` 572 | > 从第 3 行开始,插入连续 2 行的空数据 573 | > 原本第3、4行的数据会被挤压到下边 574 | 575 | 576 | ## 插入列数据 577 | 578 | ```Go 579 | package main 580 | 581 | import ( 582 | "context" 583 | 584 | "github.com/chyroc/lark" 585 | "github.com/chyroc/lark/larkext" 586 | ) 587 | 588 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 589 | _ = sheetClient.InsertCols(ctx, sheetID, 3, 2) 590 | } 591 | 592 | ``` 593 | > 从第 3 列开始,插入连续 2 列的空数据 594 | > 原本第3、4列的数据会被挤压到右边 595 | 596 | ## 增加行 597 | 598 | ```Go 599 | package main 600 | 601 | import ( 602 | "context" 603 | 604 | "github.com/chyroc/lark" 605 | "github.com/chyroc/lark/larkext" 606 | ) 607 | 608 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 609 | err := sheetClient.AddRows(ctx, sheetID, 2) 610 | 611 | _ = err 612 | } 613 | 614 | ``` 615 | > 给只有 5 行的工作表,增加 2 行 616 | 617 | ## 增加列 618 | 619 | ```Go 620 | package main 621 | 622 | import ( 623 | "context" 624 | 625 | "github.com/chyroc/lark" 626 | "github.com/chyroc/lark/larkext" 627 | ) 628 | 629 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 630 | err := sheetClient.AddCols(ctx, sheetID, 2) 631 | 632 | _ = err 633 | } 634 | 635 | ``` 636 | > 给只有 A B 两列的工作表,增加 2 列 637 | 638 | ## 追加数据 639 | 640 | ```Go 641 | package main 642 | 643 | import ( 644 | "context" 645 | 646 | "github.com/chyroc/go-ptr" 647 | "github.com/chyroc/lark" 648 | "github.com/chyroc/lark/larkext" 649 | ) 650 | 651 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 652 | err := sheetClient.Append(ctx, sheetID"!A:C", [][]lark.SheetContent{ 653 | { 654 | {String: ptr.String("string value")}, 655 | {Link: &lark.SheetValueLink{Text: "Google", Link: "https://google.com/"}}, 656 | }, 657 | { 658 | {Formula: &lark.SheetValueFormula{Text: "=A1"}}, 659 | {AtDoc: &lark.SheetValueAtDoc{ObjType: "sheet", Text: "shtcnkAi6Xr5Nl6I0LAaGxWjRzd"}}, 660 | }, 661 | }, nil) 662 | if err != nil { 663 | panic(err) 664 | } 665 | } 666 | 667 | ``` 668 | > 默认情况下,从第二行开始的非空数据会被覆盖 669 | 670 | > 可以指定追加数据模式为 `INSERT_ROWS` 671 | 672 | ## 设置行的可见性 673 | 674 | ```Go 675 | package main 676 | 677 | import ( 678 | "context" 679 | 680 | "github.com/chyroc/lark" 681 | "github.com/chyroc/lark/larkext" 682 | ) 683 | 684 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 685 | err := sheetClient.SetRowsVisible(ctx, sheetID, 2, 2, false) 686 | 687 | _ = err 688 | } 689 | 690 | ``` 691 | > 将第 2 行开始的连续的 2 行,设置为 不可见 692 | 693 | ## 设置列的可见性 694 | 695 | ```Go 696 | package main 697 | 698 | import ( 699 | "context" 700 | 701 | "github.com/chyroc/lark" 702 | "github.com/chyroc/lark/larkext" 703 | ) 704 | 705 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 706 | err := sheetClient.SetColsVisible(ctx, sheetID, 2, 2, false) 707 | 708 | _ = err 709 | } 710 | 711 | ``` 712 | > 将第 2 列开始的连续的 2 列,设置为 不可见 713 | 714 | ## 设置行的高度 715 | 716 | > 默认的行高是 27 717 | ```Go 718 | package main 719 | 720 | import ( 721 | "context" 722 | 723 | "github.com/chyroc/lark" 724 | "github.com/chyroc/lark/larkext" 725 | ) 726 | 727 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 728 | err := sheetClient.SetRowsSize(ctx, sheetID, 2, 2, 54) 729 | 730 | _ = err 731 | } 732 | 733 | ``` 734 | > 将第 2 行开始的连续 2 行的行高,设置为 54 735 | 736 | ## 设置列的宽度 737 | 738 | > 默认的列宽是 105 739 | ```Go 740 | package main 741 | 742 | import ( 743 | "context" 744 | 745 | "github.com/chyroc/lark" 746 | "github.com/chyroc/lark/larkext" 747 | ) 748 | 749 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 750 | err := sheetClient.SetRowsSize(ctx, sheetID, 2, 2, 50) 751 | 752 | _ = err 753 | } 754 | 755 | ``` 756 | > 将第 2 列开始的连续 2 列的列宽,设置为 50 757 | 758 | ## 删除行 759 | 760 | ```Go 761 | package main 762 | 763 | import ( 764 | "context" 765 | 766 | "github.com/chyroc/lark" 767 | "github.com/chyroc/lark/larkext" 768 | ) 769 | 770 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 771 | err := sheetClient.DeleteRows(ctx, sheetID, 2, 2) 772 | 773 | _ = err 774 | } 775 | 776 | ``` 777 | > 删除第 2 行开始的连续 2 行 778 | 779 | ## 删除列 780 | 781 | ```Go 782 | package main 783 | 784 | import ( 785 | "context" 786 | 787 | "github.com/chyroc/lark" 788 | "github.com/chyroc/lark/larkext" 789 | ) 790 | 791 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 792 | err := sheetClient.DeleteCols(ctx, sheetID, 2, 2) 793 | 794 | _ = err 795 | } 796 | 797 | ``` 798 | > 删除第 2 列开始的连续 2 列 799 | 800 | ## 设置单元格样式 801 | 802 | ```Go 803 | package main 804 | 805 | import ( 806 | "context" 807 | 808 | "github.com/chyroc/go-ptr" 809 | "github.com/chyroc/lark" 810 | "github.com/chyroc/lark/larkext" 811 | ) 812 | 813 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 814 | err := sheetClient.SetCellStyle(ctx, sheetID+"!A1:C3", &lark.SetSheetStyleReqAppendStyleStyle{ 815 | Font: &lark.SetSheetStyleReqAppendStyleStyleFont{ 816 | Bold: ptr.Bool(true), 817 | Italic: ptr.Bool(true), 818 | FontSize: ptr.String("10pt/1.5"), 819 | }, 820 | TextDecoration: ptr.Int64(3), 821 | HAlign: ptr.Int64(1), 822 | VAlign: ptr.Int64(1), 823 | ForeColor: ptr.String("#000000"), 824 | BackColor: ptr.String("#21d11f"), 825 | }) 826 | 827 | _ = err 828 | } 829 | 830 | ``` 831 | > 设置 A1 到 C3 区域内,加粗,删除线,切下划线,背景色 832 | 833 | ## 清除单元格样式 834 | 835 | ```Go 836 | package main 837 | 838 | import ( 839 | "context" 840 | 841 | "github.com/chyroc/lark/larkext" 842 | ) 843 | 844 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 845 | err := sheetClient.CleanCellStyle(ctx, larkext.CellRange(sheetID, 1, 1, 3, 3)) 846 | 847 | _ = err 848 | } 849 | 850 | ``` 851 | > 清除单元格上所有的样式 852 | 853 | ## 合并单元格 854 | 855 | ```Go 856 | package main 857 | 858 | import ( 859 | "context" 860 | 861 | "github.com/chyroc/lark" 862 | "github.com/chyroc/lark/larkext" 863 | ) 864 | 865 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 866 | err := sheetClient.MergeCell(ctx, sheetID+"!A1:C3", "MERGE_ALL") 867 | 868 | _ = err 869 | } 870 | 871 | ``` 872 | > mergeType 选择 MERGE_ALL,将 A1 到 C3 合并为一个单元格 873 | 874 | > mergeType 选择 MERGE_ROWS,将 A1 到 C3 按行合并为一个单元格 875 | 876 | > mergeType 选择 MERGE_COLUMNS,将 A1 到 C3 按行合并为一个单元格 877 | 878 | ## 取消合并单元格 879 | 880 | ```Go 881 | package main 882 | 883 | import ( 884 | "context" 885 | 886 | "github.com/chyroc/lark" 887 | "github.com/chyroc/lark/larkext" 888 | ) 889 | 890 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 891 | err := sheetClient.UnmergeCell(ctx, sheetID+"!A1:C3") 892 | 893 | _ = err 894 | } 895 | 896 | ``` 897 | > 将范围 A2:C2 范围内的合并单元格取消合并 898 | 899 | ## 单元格写入内容 900 | 901 | ```Go 902 | package main 903 | 904 | import ( 905 | "context" 906 | 907 | "github.com/chyroc/go-ptr" 908 | "github.com/chyroc/lark" 909 | "github.com/chyroc/lark/larkext" 910 | "github.com/davecgh/go-spew/spew" 911 | ) 912 | 913 | func exampled(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 914 | err := sheetClient.SetSheetValue(ctx, larkext.CellRange(sheetID, 1, 1, 3, 2), [][]lark.SheetContent{ 915 | { 916 | {String: ptr.String("(1,1) 字符串")}, 917 | {Int: ptr.Int64(100)}, 918 | {Link: &lark.SheetValueLink{Text: "Google", Link: "https://google.com"}}, 919 | }, 920 | { 921 | {Formula: &lark.SheetValueFormula{Text: "=A1"}}, 922 | {AtDoc: &lark.SheetValueAtDoc{ObjType: "sheet", Text: sheetClient.SheetToken()}}, 923 | }, 924 | }) 925 | _ = err 926 | } 927 | 928 | ``` 929 | > 向一个 3-2 范围的单元格写入内容,包含字符串,数字,链接,公式,文档等 930 | 931 | ## 单元格写入图片 932 | 933 | ```Go 934 | package main 935 | 936 | import ( 937 | "context" 938 | "io/ioutil" 939 | 940 | "github.com/chyroc/lark/larkext" 941 | ) 942 | 943 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID, filepath string) { 944 | images, err := ioutil.ReadFile(filepath) 945 | if err != nil { 946 | panic(err) 947 | } 948 | 949 | _ = sheetClient.SetSheetValueImage(ctx, larkext.CellRange(sheetID, 2, 2, 2, 2), images) 950 | _ = sheetClient.SetColsSize(ctx, sheetID, 2, 1, 100) 951 | _ = sheetClient.SetRowsSize(ctx, sheetID, 2, 1, 100) 952 | } 953 | 954 | ``` 955 | > 在 B2 位置写入一张图片,并将这个单元格的高和宽都设置为 100 956 | 957 | ## 批量写入单元格内容 958 | 959 | > 批量写入主要适用于单元格不连续的情况 960 | ```Go 961 | package main 962 | 963 | import ( 964 | "context" 965 | 966 | "github.com/chyroc/go-ptr" 967 | "github.com/chyroc/lark" 968 | "github.com/chyroc/lark/larkext" 969 | "github.com/davecgh/go-spew/spew" 970 | ) 971 | 972 | func exampled(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 973 | err := sheetClient.BatchSetSheetValue(ctx, []*lark.BatchSetSheetValueReqValueRange{ 974 | { 975 | Range: larkext.CellRange(sheetID, 1, 1, 1, 1), 976 | Values: [][]lark.SheetContent{ 977 | { 978 | {String: ptr.String("(1,1) 字符串")}, 979 | }, 980 | }, 981 | }, 982 | { 983 | Range: larkext.CellRange(sheetID, 2, 2, 2, 2), 984 | Values: [][]lark.SheetContent{ 985 | { 986 | {Link: &lark.SheetValueLink{Text: "Google", Link: "https://google.com"}}, 987 | }, 988 | }, 989 | }, 990 | { 991 | Range: larkext.CellRange(sheetID, 3, 3, 3, 3), 992 | Values: [][]lark.SheetContent{ 993 | { 994 | {AtDoc: &lark.SheetValueAtDoc{ObjType: "sheet", Text: sheetClient.SheetToken()}}, 995 | }, 996 | }, 997 | }, 998 | }) 999 | _ = err 1000 | } 1001 | 1002 | ``` 1003 | > 向单元格的 `(1, 1)`,`(2, 2)`,`(3, 3` 分别写入字符串,链接和文档内容 1004 | 1005 | ## 搜索表格 1006 | 1007 | ```Go 1008 | package main 1009 | 1010 | import ( 1011 | "context" 1012 | "fmt" 1013 | 1014 | "github.com/chyroc/lark" 1015 | "github.com/chyroc/lark/larkext" 1016 | ) 1017 | 1018 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 1019 | res, err := sheetClient.SearchSheet(ctx, sheetID, "6", nil) 1020 | if err != nil { 1021 | panic(err) 1022 | } 1023 | fmt.Println("march cells:", res.MatchedCells) 1024 | fmt.Println("march formula cells:", res.MatchedFormulaCells) 1025 | } 1026 | 1027 | ``` 1028 | > 前三列是数字,第四列是前三列的和,搜索:6,可以搜索出原始单元格 B2,和公式单元格 D1 1029 | 1030 | ## 替换表格 1031 | 1032 | ```Go 1033 | package main 1034 | 1035 | import ( 1036 | "context" 1037 | "fmt" 1038 | 1039 | "github.com/chyroc/lark" 1040 | "github.com/chyroc/lark/larkext" 1041 | ) 1042 | 1043 | func example(ctx context.Context, sheetClient *larkext.Sheet, sheetID string) { 1044 | _, err := sheetClient.Replace(ctx, sheetID, "6", "replace-6", nil) 1045 | if err != nil { 1046 | panic(err) 1047 | } 1048 | } 1049 | 1050 | ``` 1051 | > 前三列是数字,第四列是前三列的和,将 6 替换为 replace-6 1052 | 1053 | 1054 | # Doc / 文档 1055 | 1056 | ## 从已有的 Doc 创建 Doc 客户端 1057 | 1058 | ```Go 1059 | package main 1060 | 1061 | import ( 1062 | "context" 1063 | 1064 | "github.com/chyroc/lark" 1065 | "github.com/chyroc/lark/larkext" 1066 | ) 1067 | 1068 | func example(larkClient *lark.Lark, docToken string) { 1069 | docClient := larkext.NewDoc(larkClient, docToken) 1070 | 1071 | _ = docClient 1072 | } 1073 | 1074 | ``` 1075 | ## 获取文档元信息 1076 | 1077 | ```Go 1078 | package main 1079 | 1080 | import ( 1081 | "context" 1082 | 1083 | "github.com/chyroc/lark" 1084 | "github.com/chyroc/lark/larkext" 1085 | ) 1086 | 1087 | func example(ctx context.Context, docClient *larkext.Doc) { 1088 | meta, err := docClient.Meta(ctx) 1089 | if err != nil { 1090 | panic(err) 1091 | } 1092 | 1093 | _ = meta 1094 | } 1095 | 1096 | ``` 1097 | 1098 | ## 获取文档文本内容 1099 | 1100 | ```Go 1101 | package main 1102 | 1103 | import ( 1104 | "context" 1105 | "fmt" 1106 | 1107 | "github.com/chyroc/lark" 1108 | "github.com/chyroc/lark/larkext" 1109 | ) 1110 | 1111 | func example(ctx context.Context, docClient *larkext.Doc) { 1112 | text, err := docClient.RawContent(ctx) 1113 | if err != nil { 1114 | panic(err) 1115 | } 1116 | 1117 | fmt.Println(text) 1118 | } 1119 | 1120 | ``` 1121 | > 获取一个标题为 test 的文档的文本内容 1122 | 1123 | ## 获取文档的富文本内容 1124 | 1125 | ```Go 1126 | package main 1127 | 1128 | import ( 1129 | "context" 1130 | "fmt" 1131 | 1132 | "github.com/chyroc/lark" 1133 | "github.com/chyroc/lark/larkext" 1134 | "github.com/davecgh/go-spew/spew" 1135 | ) 1136 | 1137 | func example(ctx context.Context, docClient *larkext.Doc) { 1138 | content, err := docClient.Content(ctx) 1139 | if err != nil { 1140 | panic(err) 1141 | } 1142 | 1143 | spew.Dump(content) 1144 | } 1145 | 1146 | ``` 1147 | > 获取一个标题为 test 的文档的富文本内容 1148 | 1149 | 1150 | 1151 | 1152 | -------------------------------------------------------------------------------- /testdata/1/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": { 3 | "elements": [ 4 | { 5 | "type": "textRun", 6 | "textRun": { 7 | "text": "📔 这是一个飞书文档的例子", 8 | "style": {}, 9 | "location": { 10 | "zoneId": "0", 11 | "startIndex": 0, 12 | "endIndex": 14 13 | } 14 | } 15 | } 16 | ], 17 | "location": { 18 | "zoneId": "0", 19 | "startIndex": 0, 20 | "endIndex": 14 21 | }, 22 | "lineId": "w5mwCd" 23 | }, 24 | "body": { 25 | "blocks": [ 26 | { 27 | "type": "paragraph", 28 | "paragraph": { 29 | "elements": [ 30 | { 31 | "type": "textRun", 32 | "textRun": { 33 | "text": "这是一个飞书文档的例子,包含所有 Markdown 支持的语法", 34 | "style": {}, 35 | "location": { 36 | "zoneId": "0", 37 | "startIndex": 16, 38 | "endIndex": 47 39 | } 40 | } 41 | } 42 | ], 43 | "style": { 44 | "quote": true 45 | }, 46 | "location": { 47 | "zoneId": "0", 48 | "startIndex": 15, 49 | "endIndex": 47 50 | }, 51 | "lineId": "5YgXsL" 52 | } 53 | }, 54 | { 55 | "type": "paragraph", 56 | "paragraph": { 57 | "elements": [], 58 | "style": {}, 59 | "location": { 60 | "zoneId": "0", 61 | "startIndex": 48, 62 | "endIndex": 49 63 | }, 64 | "lineId": "FWZTIo" 65 | } 66 | }, 67 | { 68 | "type": "paragraph", 69 | "paragraph": { 70 | "elements": [ 71 | { 72 | "type": "textRun", 73 | "textRun": { 74 | "text": "标题", 75 | "style": {}, 76 | "location": { 77 | "zoneId": "0", 78 | "startIndex": 51, 79 | "endIndex": 53 80 | } 81 | } 82 | } 83 | ], 84 | "style": { 85 | "headingLevel": 1 86 | }, 87 | "location": { 88 | "zoneId": "0", 89 | "startIndex": 50, 90 | "endIndex": 53 91 | }, 92 | "lineId": "lrQpJ8" 93 | } 94 | }, 95 | { 96 | "type": "paragraph", 97 | "paragraph": { 98 | "elements": [ 99 | { 100 | "type": "textRun", 101 | "textRun": { 102 | "text": "二级标题", 103 | "style": {}, 104 | "location": { 105 | "zoneId": "0", 106 | "startIndex": 55, 107 | "endIndex": 59 108 | } 109 | } 110 | } 111 | ], 112 | "style": { 113 | "headingLevel": 2 114 | }, 115 | "location": { 116 | "zoneId": "0", 117 | "startIndex": 54, 118 | "endIndex": 59 119 | }, 120 | "lineId": "oA8dUF" 121 | } 122 | }, 123 | { 124 | "type": "paragraph", 125 | "paragraph": { 126 | "elements": [ 127 | { 128 | "type": "textRun", 129 | "textRun": { 130 | "text": "三级标题", 131 | "style": {}, 132 | "location": { 133 | "zoneId": "0", 134 | "startIndex": 61, 135 | "endIndex": 65 136 | } 137 | } 138 | } 139 | ], 140 | "style": { 141 | "headingLevel": 3 142 | }, 143 | "location": { 144 | "zoneId": "0", 145 | "startIndex": 60, 146 | "endIndex": 65 147 | }, 148 | "lineId": "DWclXO" 149 | } 150 | }, 151 | { 152 | "type": "paragraph", 153 | "paragraph": { 154 | "elements": [ 155 | { 156 | "type": "textRun", 157 | "textRun": { 158 | "text": "四级标题", 159 | "style": {}, 160 | "location": { 161 | "zoneId": "0", 162 | "startIndex": 67, 163 | "endIndex": 71 164 | } 165 | } 166 | } 167 | ], 168 | "style": { 169 | "headingLevel": 4 170 | }, 171 | "location": { 172 | "zoneId": "0", 173 | "startIndex": 66, 174 | "endIndex": 71 175 | }, 176 | "lineId": "C7dxhe" 177 | } 178 | }, 179 | { 180 | "type": "paragraph", 181 | "paragraph": { 182 | "elements": [ 183 | { 184 | "type": "textRun", 185 | "textRun": { 186 | "text": "五级标题", 187 | "style": {}, 188 | "location": { 189 | "zoneId": "0", 190 | "startIndex": 73, 191 | "endIndex": 77 192 | } 193 | } 194 | } 195 | ], 196 | "style": { 197 | "headingLevel": 5 198 | }, 199 | "location": { 200 | "zoneId": "0", 201 | "startIndex": 72, 202 | "endIndex": 77 203 | }, 204 | "lineId": "dro8Y0" 205 | } 206 | }, 207 | { 208 | "type": "paragraph", 209 | "paragraph": { 210 | "elements": [ 211 | { 212 | "type": "textRun", 213 | "textRun": { 214 | "text": "六级标题", 215 | "style": {}, 216 | "location": { 217 | "zoneId": "0", 218 | "startIndex": 79, 219 | "endIndex": 83 220 | } 221 | } 222 | } 223 | ], 224 | "style": { 225 | "headingLevel": 6 226 | }, 227 | "location": { 228 | "zoneId": "0", 229 | "startIndex": 78, 230 | "endIndex": 83 231 | }, 232 | "lineId": "BhyDB7" 233 | } 234 | }, 235 | { 236 | "type": "paragraph", 237 | "paragraph": { 238 | "elements": [ 239 | { 240 | "type": "textRun", 241 | "textRun": { 242 | "text": "正文", 243 | "style": {}, 244 | "location": { 245 | "zoneId": "0", 246 | "startIndex": 85, 247 | "endIndex": 87 248 | } 249 | } 250 | } 251 | ], 252 | "style": { 253 | "headingLevel": 1 254 | }, 255 | "location": { 256 | "zoneId": "0", 257 | "startIndex": 84, 258 | "endIndex": 87 259 | }, 260 | "lineId": "p0AQv5" 261 | } 262 | }, 263 | { 264 | "type": "paragraph", 265 | "paragraph": { 266 | "elements": [ 267 | { 268 | "type": "textRun", 269 | "textRun": { 270 | "text": "正文,这是正文,这个是正文,这个是正文啊。", 271 | "style": {}, 272 | "location": { 273 | "zoneId": "0", 274 | "startIndex": 89, 275 | "endIndex": 110 276 | } 277 | } 278 | } 279 | ], 280 | "style": {}, 281 | "location": { 282 | "zoneId": "0", 283 | "startIndex": 88, 284 | "endIndex": 110 285 | }, 286 | "lineId": "9JeXmq" 287 | } 288 | }, 289 | { 290 | "type": "paragraph", 291 | "paragraph": { 292 | "elements": [ 293 | { 294 | "type": "textRun", 295 | "textRun": { 296 | "text": "正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。正文,这是正文,这个是正文,这个是正文啊。", 297 | "style": {}, 298 | "location": { 299 | "zoneId": "0", 300 | "startIndex": 112, 301 | "endIndex": 259 302 | } 303 | } 304 | } 305 | ], 306 | "style": {}, 307 | "location": { 308 | "zoneId": "0", 309 | "startIndex": 111, 310 | "endIndex": 259 311 | }, 312 | "lineId": "eDchaF" 313 | } 314 | }, 315 | { 316 | "type": "paragraph", 317 | "paragraph": { 318 | "elements": [ 319 | { 320 | "type": "textRun", 321 | "textRun": { 322 | "text": "列表", 323 | "style": {}, 324 | "location": { 325 | "zoneId": "0", 326 | "startIndex": 261, 327 | "endIndex": 263 328 | } 329 | } 330 | } 331 | ], 332 | "style": { 333 | "headingLevel": 1 334 | }, 335 | "location": { 336 | "zoneId": "0", 337 | "startIndex": 260, 338 | "endIndex": 263 339 | }, 340 | "lineId": "Y2oAMb" 341 | } 342 | }, 343 | { 344 | "type": "paragraph", 345 | "paragraph": { 346 | "elements": [ 347 | { 348 | "type": "textRun", 349 | "textRun": { 350 | "text": "有序列表", 351 | "style": {}, 352 | "location": { 353 | "zoneId": "0", 354 | "startIndex": 265, 355 | "endIndex": 269 356 | } 357 | } 358 | } 359 | ], 360 | "style": { 361 | "headingLevel": 2 362 | }, 363 | "location": { 364 | "zoneId": "0", 365 | "startIndex": 264, 366 | "endIndex": 269 367 | }, 368 | "lineId": "BofKka" 369 | } 370 | }, 371 | { 372 | "type": "paragraph", 373 | "paragraph": { 374 | "elements": [ 375 | { 376 | "type": "textRun", 377 | "textRun": { 378 | "text": "1", 379 | "style": {}, 380 | "location": { 381 | "zoneId": "0", 382 | "startIndex": 271, 383 | "endIndex": 272 384 | } 385 | } 386 | } 387 | ], 388 | "style": { 389 | "list": { 390 | "type": "number", 391 | "indentLevel": 1, 392 | "number": 1 393 | } 394 | }, 395 | "location": { 396 | "zoneId": "0", 397 | "startIndex": 270, 398 | "endIndex": 272 399 | }, 400 | "lineId": "hyR5MJ" 401 | } 402 | }, 403 | { 404 | "type": "paragraph", 405 | "paragraph": { 406 | "elements": [ 407 | { 408 | "type": "textRun", 409 | "textRun": { 410 | "text": "A", 411 | "style": {}, 412 | "location": { 413 | "zoneId": "0", 414 | "startIndex": 274, 415 | "endIndex": 275 416 | } 417 | } 418 | } 419 | ], 420 | "style": { 421 | "list": { 422 | "type": "number", 423 | "indentLevel": 2, 424 | "number": 1 425 | } 426 | }, 427 | "location": { 428 | "zoneId": "0", 429 | "startIndex": 273, 430 | "endIndex": 275 431 | }, 432 | "lineId": "eESxIU" 433 | } 434 | }, 435 | { 436 | "type": "paragraph", 437 | "paragraph": { 438 | "elements": [ 439 | { 440 | "type": "textRun", 441 | "textRun": { 442 | "text": "i", 443 | "style": {}, 444 | "location": { 445 | "zoneId": "0", 446 | "startIndex": 277, 447 | "endIndex": 278 448 | } 449 | } 450 | } 451 | ], 452 | "style": { 453 | "list": { 454 | "type": "number", 455 | "indentLevel": 3, 456 | "number": 1 457 | } 458 | }, 459 | "location": { 460 | "zoneId": "0", 461 | "startIndex": 276, 462 | "endIndex": 278 463 | }, 464 | "lineId": "nWlL7c" 465 | } 466 | }, 467 | { 468 | "type": "paragraph", 469 | "paragraph": { 470 | "elements": [ 471 | { 472 | "type": "textRun", 473 | "textRun": { 474 | "text": "1", 475 | "style": {}, 476 | "location": { 477 | "zoneId": "0", 478 | "startIndex": 280, 479 | "endIndex": 281 480 | } 481 | } 482 | } 483 | ], 484 | "style": { 485 | "list": { 486 | "type": "number", 487 | "indentLevel": 4, 488 | "number": 1 489 | } 490 | }, 491 | "location": { 492 | "zoneId": "0", 493 | "startIndex": 279, 494 | "endIndex": 281 495 | }, 496 | "lineId": "FtToyR" 497 | } 498 | }, 499 | { 500 | "type": "paragraph", 501 | "paragraph": { 502 | "elements": [ 503 | { 504 | "type": "textRun", 505 | "textRun": { 506 | "text": "a", 507 | "style": {}, 508 | "location": { 509 | "zoneId": "0", 510 | "startIndex": 283, 511 | "endIndex": 284 512 | } 513 | } 514 | } 515 | ], 516 | "style": { 517 | "list": { 518 | "type": "number", 519 | "indentLevel": 5, 520 | "number": 1 521 | } 522 | }, 523 | "location": { 524 | "zoneId": "0", 525 | "startIndex": 282, 526 | "endIndex": 284 527 | }, 528 | "lineId": "uUw94E" 529 | } 530 | }, 531 | { 532 | "type": "paragraph", 533 | "paragraph": { 534 | "elements": [ 535 | { 536 | "type": "textRun", 537 | "textRun": { 538 | "text": "b", 539 | "style": {}, 540 | "location": { 541 | "zoneId": "0", 542 | "startIndex": 286, 543 | "endIndex": 287 544 | } 545 | } 546 | } 547 | ], 548 | "style": { 549 | "list": { 550 | "type": "number", 551 | "indentLevel": 5, 552 | "number": 2 553 | } 554 | }, 555 | "location": { 556 | "zoneId": "0", 557 | "startIndex": 285, 558 | "endIndex": 287 559 | }, 560 | "lineId": "PtEfmX" 561 | } 562 | }, 563 | { 564 | "type": "paragraph", 565 | "paragraph": { 566 | "elements": [ 567 | { 568 | "type": "textRun", 569 | "textRun": { 570 | "text": "X", 571 | "style": {}, 572 | "location": { 573 | "zoneId": "0", 574 | "startIndex": 289, 575 | "endIndex": 290 576 | } 577 | } 578 | } 579 | ], 580 | "style": { 581 | "list": { 582 | "type": "number", 583 | "indentLevel": 5, 584 | "number": 3 585 | } 586 | }, 587 | "location": { 588 | "zoneId": "0", 589 | "startIndex": 288, 590 | "endIndex": 290 591 | }, 592 | "lineId": "lCo4wo" 593 | } 594 | }, 595 | { 596 | "type": "paragraph", 597 | "paragraph": { 598 | "elements": [ 599 | { 600 | "type": "textRun", 601 | "textRun": { 602 | "text": "2", 603 | "style": {}, 604 | "location": { 605 | "zoneId": "0", 606 | "startIndex": 292, 607 | "endIndex": 293 608 | } 609 | } 610 | } 611 | ], 612 | "style": { 613 | "list": { 614 | "type": "number", 615 | "indentLevel": 4, 616 | "number": 2 617 | } 618 | }, 619 | "location": { 620 | "zoneId": "0", 621 | "startIndex": 291, 622 | "endIndex": 293 623 | }, 624 | "lineId": "6CWfxH" 625 | } 626 | }, 627 | { 628 | "type": "paragraph", 629 | "paragraph": { 630 | "elements": [ 631 | { 632 | "type": "textRun", 633 | "textRun": { 634 | "text": "3", 635 | "style": {}, 636 | "location": { 637 | "zoneId": "0", 638 | "startIndex": 295, 639 | "endIndex": 296 640 | } 641 | } 642 | } 643 | ], 644 | "style": { 645 | "list": { 646 | "type": "number", 647 | "indentLevel": 4, 648 | "number": 3 649 | } 650 | }, 651 | "location": { 652 | "zoneId": "0", 653 | "startIndex": 294, 654 | "endIndex": 296 655 | }, 656 | "lineId": "Gf7Blu" 657 | } 658 | }, 659 | { 660 | "type": "paragraph", 661 | "paragraph": { 662 | "elements": [ 663 | { 664 | "type": "textRun", 665 | "textRun": { 666 | "text": "Ii", 667 | "style": {}, 668 | "location": { 669 | "zoneId": "0", 670 | "startIndex": 298, 671 | "endIndex": 300 672 | } 673 | } 674 | } 675 | ], 676 | "style": { 677 | "list": { 678 | "type": "number", 679 | "indentLevel": 3, 680 | "number": 2 681 | } 682 | }, 683 | "location": { 684 | "zoneId": "0", 685 | "startIndex": 297, 686 | "endIndex": 300 687 | }, 688 | "lineId": "l2hzDD" 689 | } 690 | }, 691 | { 692 | "type": "paragraph", 693 | "paragraph": { 694 | "elements": [ 695 | { 696 | "type": "textRun", 697 | "textRun": { 698 | "text": "Iii", 699 | "style": {}, 700 | "location": { 701 | "zoneId": "0", 702 | "startIndex": 302, 703 | "endIndex": 305 704 | } 705 | } 706 | } 707 | ], 708 | "style": { 709 | "list": { 710 | "type": "number", 711 | "indentLevel": 3, 712 | "number": 3 713 | } 714 | }, 715 | "location": { 716 | "zoneId": "0", 717 | "startIndex": 301, 718 | "endIndex": 305 719 | }, 720 | "lineId": "foKYMi" 721 | } 722 | }, 723 | { 724 | "type": "paragraph", 725 | "paragraph": { 726 | "elements": [ 727 | { 728 | "type": "textRun", 729 | "textRun": { 730 | "text": "iv", 731 | "style": {}, 732 | "location": { 733 | "zoneId": "0", 734 | "startIndex": 307, 735 | "endIndex": 309 736 | } 737 | } 738 | } 739 | ], 740 | "style": { 741 | "list": { 742 | "type": "number", 743 | "indentLevel": 3, 744 | "number": 4 745 | } 746 | }, 747 | "location": { 748 | "zoneId": "0", 749 | "startIndex": 306, 750 | "endIndex": 309 751 | }, 752 | "lineId": "BMG6Wk" 753 | } 754 | }, 755 | { 756 | "type": "paragraph", 757 | "paragraph": { 758 | "elements": [ 759 | { 760 | "type": "textRun", 761 | "textRun": { 762 | "text": "Dd", 763 | "style": {}, 764 | "location": { 765 | "zoneId": "0", 766 | "startIndex": 311, 767 | "endIndex": 313 768 | } 769 | } 770 | } 771 | ], 772 | "style": { 773 | "list": { 774 | "type": "number", 775 | "indentLevel": 3, 776 | "number": 5 777 | } 778 | }, 779 | "location": { 780 | "zoneId": "0", 781 | "startIndex": 310, 782 | "endIndex": 313 783 | }, 784 | "lineId": "h6A0Un" 785 | } 786 | }, 787 | { 788 | "type": "paragraph", 789 | "paragraph": { 790 | "elements": [ 791 | { 792 | "type": "textRun", 793 | "textRun": { 794 | "text": "B", 795 | "style": {}, 796 | "location": { 797 | "zoneId": "0", 798 | "startIndex": 315, 799 | "endIndex": 316 800 | } 801 | } 802 | } 803 | ], 804 | "style": { 805 | "list": { 806 | "type": "number", 807 | "indentLevel": 2, 808 | "number": 2 809 | } 810 | }, 811 | "location": { 812 | "zoneId": "0", 813 | "startIndex": 314, 814 | "endIndex": 316 815 | }, 816 | "lineId": "sWFyTC" 817 | } 818 | }, 819 | { 820 | "type": "paragraph", 821 | "paragraph": { 822 | "elements": [ 823 | { 824 | "type": "textRun", 825 | "textRun": { 826 | "text": "C", 827 | "style": {}, 828 | "location": { 829 | "zoneId": "0", 830 | "startIndex": 318, 831 | "endIndex": 319 832 | } 833 | } 834 | } 835 | ], 836 | "style": { 837 | "list": { 838 | "type": "number", 839 | "indentLevel": 2, 840 | "number": 3 841 | } 842 | }, 843 | "location": { 844 | "zoneId": "0", 845 | "startIndex": 317, 846 | "endIndex": 319 847 | }, 848 | "lineId": "UUim3Q" 849 | } 850 | }, 851 | { 852 | "type": "paragraph", 853 | "paragraph": { 854 | "elements": [ 855 | { 856 | "type": "textRun", 857 | "textRun": { 858 | "text": "D", 859 | "style": {}, 860 | "location": { 861 | "zoneId": "0", 862 | "startIndex": 321, 863 | "endIndex": 322 864 | } 865 | } 866 | } 867 | ], 868 | "style": { 869 | "list": { 870 | "type": "number", 871 | "indentLevel": 2, 872 | "number": 4 873 | } 874 | }, 875 | "location": { 876 | "zoneId": "0", 877 | "startIndex": 320, 878 | "endIndex": 322 879 | }, 880 | "lineId": "hs28H8" 881 | } 882 | }, 883 | { 884 | "type": "paragraph", 885 | "paragraph": { 886 | "elements": [ 887 | { 888 | "type": "textRun", 889 | "textRun": { 890 | "text": "E", 891 | "style": {}, 892 | "location": { 893 | "zoneId": "0", 894 | "startIndex": 324, 895 | "endIndex": 325 896 | } 897 | } 898 | } 899 | ], 900 | "style": { 901 | "list": { 902 | "type": "number", 903 | "indentLevel": 2, 904 | "number": 5 905 | } 906 | }, 907 | "location": { 908 | "zoneId": "0", 909 | "startIndex": 323, 910 | "endIndex": 325 911 | }, 912 | "lineId": "hkfle8" 913 | } 914 | }, 915 | { 916 | "type": "paragraph", 917 | "paragraph": { 918 | "elements": [ 919 | { 920 | "type": "textRun", 921 | "textRun": { 922 | "text": "F", 923 | "style": {}, 924 | "location": { 925 | "zoneId": "0", 926 | "startIndex": 327, 927 | "endIndex": 328 928 | } 929 | } 930 | } 931 | ], 932 | "style": { 933 | "list": { 934 | "type": "number", 935 | "indentLevel": 2, 936 | "number": 6 937 | } 938 | }, 939 | "location": { 940 | "zoneId": "0", 941 | "startIndex": 326, 942 | "endIndex": 328 943 | }, 944 | "lineId": "EpwoBT" 945 | } 946 | }, 947 | { 948 | "type": "paragraph", 949 | "paragraph": { 950 | "elements": [ 951 | { 952 | "type": "textRun", 953 | "textRun": { 954 | "text": "G", 955 | "style": {}, 956 | "location": { 957 | "zoneId": "0", 958 | "startIndex": 330, 959 | "endIndex": 331 960 | } 961 | } 962 | } 963 | ], 964 | "style": { 965 | "list": { 966 | "type": "number", 967 | "indentLevel": 2, 968 | "number": 7 969 | } 970 | }, 971 | "location": { 972 | "zoneId": "0", 973 | "startIndex": 329, 974 | "endIndex": 331 975 | }, 976 | "lineId": "JKHlL4" 977 | } 978 | }, 979 | { 980 | "type": "paragraph", 981 | "paragraph": { 982 | "elements": [ 983 | { 984 | "type": "textRun", 985 | "textRun": { 986 | "text": "2", 987 | "style": {}, 988 | "location": { 989 | "zoneId": "0", 990 | "startIndex": 333, 991 | "endIndex": 334 992 | } 993 | } 994 | } 995 | ], 996 | "style": { 997 | "list": { 998 | "type": "number", 999 | "indentLevel": 1, 1000 | "number": 2 1001 | } 1002 | }, 1003 | "location": { 1004 | "zoneId": "0", 1005 | "startIndex": 332, 1006 | "endIndex": 334 1007 | }, 1008 | "lineId": "oCwRKj" 1009 | } 1010 | }, 1011 | { 1012 | "type": "paragraph", 1013 | "paragraph": { 1014 | "elements": [ 1015 | { 1016 | "type": "textRun", 1017 | "textRun": { 1018 | "text": "3", 1019 | "style": {}, 1020 | "location": { 1021 | "zoneId": "0", 1022 | "startIndex": 336, 1023 | "endIndex": 337 1024 | } 1025 | } 1026 | } 1027 | ], 1028 | "style": { 1029 | "list": { 1030 | "type": "number", 1031 | "indentLevel": 1, 1032 | "number": 3 1033 | } 1034 | }, 1035 | "location": { 1036 | "zoneId": "0", 1037 | "startIndex": 335, 1038 | "endIndex": 337 1039 | }, 1040 | "lineId": "mBS7x6" 1041 | } 1042 | }, 1043 | { 1044 | "type": "paragraph", 1045 | "paragraph": { 1046 | "elements": [ 1047 | { 1048 | "type": "textRun", 1049 | "textRun": { 1050 | "text": "无序列表", 1051 | "style": {}, 1052 | "location": { 1053 | "zoneId": "0", 1054 | "startIndex": 339, 1055 | "endIndex": 343 1056 | } 1057 | } 1058 | } 1059 | ], 1060 | "style": { 1061 | "headingLevel": 2 1062 | }, 1063 | "location": { 1064 | "zoneId": "0", 1065 | "startIndex": 338, 1066 | "endIndex": 343 1067 | }, 1068 | "lineId": "cYJS3t" 1069 | } 1070 | }, 1071 | { 1072 | "type": "paragraph", 1073 | "paragraph": { 1074 | "elements": [ 1075 | { 1076 | "type": "textRun", 1077 | "textRun": { 1078 | "text": "X", 1079 | "style": {}, 1080 | "location": { 1081 | "zoneId": "0", 1082 | "startIndex": 345, 1083 | "endIndex": 346 1084 | } 1085 | } 1086 | } 1087 | ], 1088 | "style": { 1089 | "list": { 1090 | "type": "bullet", 1091 | "indentLevel": 1 1092 | } 1093 | }, 1094 | "location": { 1095 | "zoneId": "0", 1096 | "startIndex": 344, 1097 | "endIndex": 346 1098 | }, 1099 | "lineId": "xkMy8J" 1100 | } 1101 | }, 1102 | { 1103 | "type": "paragraph", 1104 | "paragraph": { 1105 | "elements": [ 1106 | { 1107 | "type": "textRun", 1108 | "textRun": { 1109 | "text": "XX", 1110 | "style": {}, 1111 | "location": { 1112 | "zoneId": "0", 1113 | "startIndex": 348, 1114 | "endIndex": 350 1115 | } 1116 | } 1117 | } 1118 | ], 1119 | "style": { 1120 | "list": { 1121 | "type": "bullet", 1122 | "indentLevel": 2 1123 | } 1124 | }, 1125 | "location": { 1126 | "zoneId": "0", 1127 | "startIndex": 347, 1128 | "endIndex": 350 1129 | }, 1130 | "lineId": "ZXtRun" 1131 | } 1132 | }, 1133 | { 1134 | "type": "paragraph", 1135 | "paragraph": { 1136 | "elements": [ 1137 | { 1138 | "type": "textRun", 1139 | "textRun": { 1140 | "text": "XXX", 1141 | "style": {}, 1142 | "location": { 1143 | "zoneId": "0", 1144 | "startIndex": 352, 1145 | "endIndex": 355 1146 | } 1147 | } 1148 | } 1149 | ], 1150 | "style": { 1151 | "list": { 1152 | "type": "bullet", 1153 | "indentLevel": 3 1154 | } 1155 | }, 1156 | "location": { 1157 | "zoneId": "0", 1158 | "startIndex": 351, 1159 | "endIndex": 355 1160 | }, 1161 | "lineId": "xQs4TX" 1162 | } 1163 | }, 1164 | { 1165 | "type": "paragraph", 1166 | "paragraph": { 1167 | "elements": [ 1168 | { 1169 | "type": "textRun", 1170 | "textRun": { 1171 | "text": "XXX ", 1172 | "style": {}, 1173 | "location": { 1174 | "zoneId": "0", 1175 | "startIndex": 357, 1176 | "endIndex": 361 1177 | } 1178 | } 1179 | } 1180 | ], 1181 | "style": { 1182 | "list": { 1183 | "type": "bullet", 1184 | "indentLevel": 4 1185 | } 1186 | }, 1187 | "location": { 1188 | "zoneId": "0", 1189 | "startIndex": 356, 1190 | "endIndex": 361 1191 | }, 1192 | "lineId": "5xwp5c" 1193 | } 1194 | }, 1195 | { 1196 | "type": "paragraph", 1197 | "paragraph": { 1198 | "elements": [ 1199 | { 1200 | "type": "textRun", 1201 | "textRun": { 1202 | "text": "XXXX", 1203 | "style": {}, 1204 | "location": { 1205 | "zoneId": "0", 1206 | "startIndex": 363, 1207 | "endIndex": 367 1208 | } 1209 | } 1210 | } 1211 | ], 1212 | "style": { 1213 | "list": { 1214 | "type": "bullet", 1215 | "indentLevel": 5 1216 | } 1217 | }, 1218 | "location": { 1219 | "zoneId": "0", 1220 | "startIndex": 362, 1221 | "endIndex": 367 1222 | }, 1223 | "lineId": "9NPG1C" 1224 | } 1225 | }, 1226 | { 1227 | "type": "paragraph", 1228 | "paragraph": { 1229 | "elements": [ 1230 | { 1231 | "type": "textRun", 1232 | "textRun": { 1233 | "text": "X", 1234 | "style": {}, 1235 | "location": { 1236 | "zoneId": "0", 1237 | "startIndex": 369, 1238 | "endIndex": 370 1239 | } 1240 | } 1241 | } 1242 | ], 1243 | "style": { 1244 | "list": { 1245 | "type": "bullet", 1246 | "indentLevel": 1 1247 | } 1248 | }, 1249 | "location": { 1250 | "zoneId": "0", 1251 | "startIndex": 368, 1252 | "endIndex": 370 1253 | }, 1254 | "lineId": "w6z89Q" 1255 | } 1256 | }, 1257 | { 1258 | "type": "paragraph", 1259 | "paragraph": { 1260 | "elements": [ 1261 | { 1262 | "type": "textRun", 1263 | "textRun": { 1264 | "text": "X", 1265 | "style": {}, 1266 | "location": { 1267 | "zoneId": "0", 1268 | "startIndex": 372, 1269 | "endIndex": 373 1270 | } 1271 | } 1272 | } 1273 | ], 1274 | "style": { 1275 | "list": { 1276 | "type": "bullet", 1277 | "indentLevel": 1 1278 | } 1279 | }, 1280 | "location": { 1281 | "zoneId": "0", 1282 | "startIndex": 371, 1283 | "endIndex": 373 1284 | }, 1285 | "lineId": "WyvFcg" 1286 | } 1287 | }, 1288 | { 1289 | "type": "paragraph", 1290 | "paragraph": { 1291 | "elements": [ 1292 | { 1293 | "type": "textRun", 1294 | "textRun": { 1295 | "text": "任务列表", 1296 | "style": {}, 1297 | "location": { 1298 | "zoneId": "0", 1299 | "startIndex": 375, 1300 | "endIndex": 379 1301 | } 1302 | } 1303 | } 1304 | ], 1305 | "style": { 1306 | "headingLevel": 1 1307 | }, 1308 | "location": { 1309 | "zoneId": "0", 1310 | "startIndex": 374, 1311 | "endIndex": 379 1312 | }, 1313 | "lineId": "WJNbbj" 1314 | } 1315 | }, 1316 | { 1317 | "type": "paragraph", 1318 | "paragraph": { 1319 | "elements": [ 1320 | { 1321 | "type": "textRun", 1322 | "textRun": { 1323 | "text": "任务 x", 1324 | "style": {}, 1325 | "location": { 1326 | "zoneId": "0", 1327 | "startIndex": 381, 1328 | "endIndex": 385 1329 | } 1330 | } 1331 | } 1332 | ], 1333 | "style": { 1334 | "list": { 1335 | "type": "checkBox", 1336 | "indentLevel": 1 1337 | }, 1338 | "todoUUID": "83d7cb7b-4e12-4da9-a884-789e57a61f53" 1339 | }, 1340 | "location": { 1341 | "zoneId": "0", 1342 | "startIndex": 380, 1343 | "endIndex": 385 1344 | }, 1345 | "lineId": "ix0zun" 1346 | } 1347 | }, 1348 | { 1349 | "type": "paragraph", 1350 | "paragraph": { 1351 | "elements": [ 1352 | { 1353 | "type": "textRun", 1354 | "textRun": { 1355 | "text": "任务 xx", 1356 | "style": {}, 1357 | "location": { 1358 | "zoneId": "0", 1359 | "startIndex": 387, 1360 | "endIndex": 392 1361 | } 1362 | } 1363 | } 1364 | ], 1365 | "style": { 1366 | "list": { 1367 | "type": "checkBox", 1368 | "indentLevel": 2 1369 | }, 1370 | "todoUUID": "f03cbebc-5c6c-4f39-8929-da5fb0b99660" 1371 | }, 1372 | "location": { 1373 | "zoneId": "0", 1374 | "startIndex": 386, 1375 | "endIndex": 392 1376 | }, 1377 | "lineId": "Lg7v5t" 1378 | } 1379 | }, 1380 | { 1381 | "type": "paragraph", 1382 | "paragraph": { 1383 | "elements": [ 1384 | { 1385 | "type": "textRun", 1386 | "textRun": { 1387 | "text": "任务 x", 1388 | "style": {}, 1389 | "location": { 1390 | "zoneId": "0", 1391 | "startIndex": 394, 1392 | "endIndex": 398 1393 | } 1394 | } 1395 | } 1396 | ], 1397 | "style": { 1398 | "list": { 1399 | "type": "checkBox", 1400 | "indentLevel": 1 1401 | }, 1402 | "todoUUID": "72983fbd-dc42-4a1a-a102-c60a3149dca0" 1403 | }, 1404 | "location": { 1405 | "zoneId": "0", 1406 | "startIndex": 393, 1407 | "endIndex": 398 1408 | }, 1409 | "lineId": "Wyu7D2" 1410 | } 1411 | }, 1412 | { 1413 | "type": "paragraph", 1414 | "paragraph": { 1415 | "elements": [ 1416 | { 1417 | "type": "textRun", 1418 | "textRun": { 1419 | "text": "完成的任务 x", 1420 | "style": {}, 1421 | "location": { 1422 | "zoneId": "0", 1423 | "startIndex": 400, 1424 | "endIndex": 407 1425 | } 1426 | } 1427 | } 1428 | ], 1429 | "style": { 1430 | "list": { 1431 | "type": "checkedBox", 1432 | "indentLevel": 1 1433 | }, 1434 | "todoUUID": "f652f07f-9d7e-409a-94c6-fac345298ec8" 1435 | }, 1436 | "location": { 1437 | "zoneId": "0", 1438 | "startIndex": 399, 1439 | "endIndex": 407 1440 | }, 1441 | "lineId": "8dkeY3" 1442 | } 1443 | }, 1444 | { 1445 | "type": "paragraph", 1446 | "paragraph": { 1447 | "elements": [ 1448 | { 1449 | "type": "textRun", 1450 | "textRun": { 1451 | "text": "高亮块", 1452 | "style": {}, 1453 | "location": { 1454 | "zoneId": "0", 1455 | "startIndex": 409, 1456 | "endIndex": 412 1457 | } 1458 | } 1459 | } 1460 | ], 1461 | "style": { 1462 | "headingLevel": 1 1463 | }, 1464 | "location": { 1465 | "zoneId": "0", 1466 | "startIndex": 408, 1467 | "endIndex": 412 1468 | }, 1469 | "lineId": "af2U0l" 1470 | } 1471 | }, 1472 | { 1473 | "type": "callout", 1474 | "callout": { 1475 | "location": { 1476 | "zoneId": "0", 1477 | "startIndex": 413, 1478 | "endIndex": 414 1479 | }, 1480 | "calloutEmojiId": "exclamation", 1481 | "calloutBackgroundColor": { 1482 | "red": 246, 1483 | "green": 241, 1484 | "blue": 254, 1485 | "alpha": 1 1486 | }, 1487 | "calloutBorderColor": { 1488 | "red": 205, 1489 | "green": 178, 1490 | "blue": 250, 1491 | "alpha": 1 1492 | }, 1493 | "zoneId": "suv92xjkqr", 1494 | "body": { 1495 | "blocks": [ 1496 | { 1497 | "type": "paragraph", 1498 | "paragraph": { 1499 | "elements": [ 1500 | { 1501 | "type": "textRun", 1502 | "textRun": { 1503 | "text": "高亮块", 1504 | "style": {}, 1505 | "location": { 1506 | "zoneId": "suv92xjkqr", 1507 | "startIndex": 1, 1508 | "endIndex": 4 1509 | } 1510 | } 1511 | } 1512 | ], 1513 | "style": {}, 1514 | "location": { 1515 | "zoneId": "suv92xjkqr", 1516 | "startIndex": 0, 1517 | "endIndex": 4 1518 | }, 1519 | "lineId": "NMGpSb" 1520 | } 1521 | }, 1522 | { 1523 | "type": "paragraph", 1524 | "paragraph": { 1525 | "elements": [], 1526 | "style": {}, 1527 | "location": { 1528 | "zoneId": "suv92xjkqr", 1529 | "startIndex": 5, 1530 | "endIndex": 6 1531 | }, 1532 | "lineId": "oKhl46" 1533 | } 1534 | }, 1535 | { 1536 | "type": "paragraph", 1537 | "paragraph": { 1538 | "elements": [ 1539 | { 1540 | "type": "textRun", 1541 | "textRun": { 1542 | "text": "高亮块支持颜色,转成 Markdown 后不支持", 1543 | "style": {}, 1544 | "location": { 1545 | "zoneId": "suv92xjkqr", 1546 | "startIndex": 8, 1547 | "endIndex": 32 1548 | } 1549 | } 1550 | } 1551 | ], 1552 | "style": {}, 1553 | "location": { 1554 | "zoneId": "suv92xjkqr", 1555 | "startIndex": 7, 1556 | "endIndex": 32 1557 | }, 1558 | "lineId": "8zkuoG" 1559 | } 1560 | } 1561 | ] 1562 | } 1563 | } 1564 | }, 1565 | { 1566 | "type": "paragraph", 1567 | "paragraph": { 1568 | "elements": [ 1569 | { 1570 | "type": "textRun", 1571 | "textRun": { 1572 | "text": "分割线", 1573 | "style": {}, 1574 | "location": { 1575 | "zoneId": "0", 1576 | "startIndex": 416, 1577 | "endIndex": 419 1578 | } 1579 | } 1580 | } 1581 | ], 1582 | "style": { 1583 | "headingLevel": 1 1584 | }, 1585 | "location": { 1586 | "zoneId": "0", 1587 | "startIndex": 415, 1588 | "endIndex": 419 1589 | }, 1590 | "lineId": "8IGqPs" 1591 | } 1592 | }, 1593 | { 1594 | "type": "horizontalLine", 1595 | "horizontalLine": { 1596 | "location": { 1597 | "zoneId": "0", 1598 | "startIndex": 420, 1599 | "endIndex": 422 1600 | } 1601 | } 1602 | }, 1603 | { 1604 | "type": "paragraph", 1605 | "paragraph": { 1606 | "elements": [ 1607 | { 1608 | "type": "textRun", 1609 | "textRun": { 1610 | "text": "引用", 1611 | "style": {}, 1612 | "location": { 1613 | "zoneId": "0", 1614 | "startIndex": 424, 1615 | "endIndex": 426 1616 | } 1617 | } 1618 | } 1619 | ], 1620 | "style": { 1621 | "headingLevel": 1 1622 | }, 1623 | "location": { 1624 | "zoneId": "0", 1625 | "startIndex": 423, 1626 | "endIndex": 426 1627 | }, 1628 | "lineId": "luc8JM" 1629 | } 1630 | }, 1631 | { 1632 | "type": "paragraph", 1633 | "paragraph": { 1634 | "elements": [ 1635 | { 1636 | "type": "textRun", 1637 | "textRun": { 1638 | "text": "这是一个引用", 1639 | "style": {}, 1640 | "location": { 1641 | "zoneId": "0", 1642 | "startIndex": 428, 1643 | "endIndex": 434 1644 | } 1645 | } 1646 | } 1647 | ], 1648 | "style": { 1649 | "quote": true 1650 | }, 1651 | "location": { 1652 | "zoneId": "0", 1653 | "startIndex": 427, 1654 | "endIndex": 434 1655 | }, 1656 | "lineId": "FBPOmk" 1657 | } 1658 | }, 1659 | { 1660 | "type": "paragraph", 1661 | "paragraph": { 1662 | "elements": [], 1663 | "style": {}, 1664 | "location": { 1665 | "zoneId": "0", 1666 | "startIndex": 435, 1667 | "endIndex": 436 1668 | }, 1669 | "lineId": "TG3tDF" 1670 | } 1671 | }, 1672 | { 1673 | "type": "paragraph", 1674 | "paragraph": { 1675 | "elements": [ 1676 | { 1677 | "type": "textRun", 1678 | "textRun": { 1679 | "text": "这是一个引用,有 tab", 1680 | "style": {}, 1681 | "location": { 1682 | "zoneId": "0", 1683 | "startIndex": 438, 1684 | "endIndex": 450 1685 | } 1686 | } 1687 | } 1688 | ], 1689 | "style": { 1690 | "quote": true 1691 | }, 1692 | "location": { 1693 | "zoneId": "0", 1694 | "startIndex": 437, 1695 | "endIndex": 450 1696 | }, 1697 | "lineId": "x2jzzb" 1698 | } 1699 | }, 1700 | { 1701 | "type": "paragraph", 1702 | "paragraph": { 1703 | "elements": [], 1704 | "style": {}, 1705 | "location": { 1706 | "zoneId": "0", 1707 | "startIndex": 451, 1708 | "endIndex": 452 1709 | }, 1710 | "lineId": "YbH3IU" 1711 | } 1712 | }, 1713 | { 1714 | "type": "paragraph", 1715 | "paragraph": { 1716 | "elements": [ 1717 | { 1718 | "type": "textRun", 1719 | "textRun": { 1720 | "text": "引用行 1", 1721 | "style": {}, 1722 | "location": { 1723 | "zoneId": "0", 1724 | "startIndex": 454, 1725 | "endIndex": 459 1726 | } 1727 | } 1728 | } 1729 | ], 1730 | "style": { 1731 | "quote": true 1732 | }, 1733 | "location": { 1734 | "zoneId": "0", 1735 | "startIndex": 453, 1736 | "endIndex": 459 1737 | }, 1738 | "lineId": "eHESfV" 1739 | } 1740 | }, 1741 | { 1742 | "type": "paragraph", 1743 | "paragraph": { 1744 | "elements": [ 1745 | { 1746 | "type": "textRun", 1747 | "textRun": { 1748 | "text": "引用行 2", 1749 | "style": {}, 1750 | "location": { 1751 | "zoneId": "0", 1752 | "startIndex": 461, 1753 | "endIndex": 466 1754 | } 1755 | } 1756 | } 1757 | ], 1758 | "style": { 1759 | "quote": true 1760 | }, 1761 | "location": { 1762 | "zoneId": "0", 1763 | "startIndex": 460, 1764 | "endIndex": 466 1765 | }, 1766 | "lineId": "ARhcPm" 1767 | } 1768 | }, 1769 | { 1770 | "type": "paragraph", 1771 | "paragraph": { 1772 | "elements": [ 1773 | { 1774 | "type": "textRun", 1775 | "textRun": { 1776 | "text": "引用行 3", 1777 | "style": {}, 1778 | "location": { 1779 | "zoneId": "0", 1780 | "startIndex": 468, 1781 | "endIndex": 473 1782 | } 1783 | } 1784 | } 1785 | ], 1786 | "style": { 1787 | "quote": true 1788 | }, 1789 | "location": { 1790 | "zoneId": "0", 1791 | "startIndex": 467, 1792 | "endIndex": 473 1793 | }, 1794 | "lineId": "GPapOS" 1795 | } 1796 | }, 1797 | { 1798 | "type": "paragraph", 1799 | "paragraph": { 1800 | "elements": [], 1801 | "style": {}, 1802 | "location": { 1803 | "zoneId": "0", 1804 | "startIndex": 474, 1805 | "endIndex": 475 1806 | }, 1807 | "lineId": "8nzIdP" 1808 | } 1809 | }, 1810 | { 1811 | "type": "paragraph", 1812 | "paragraph": { 1813 | "elements": [ 1814 | { 1815 | "type": "textRun", 1816 | "textRun": { 1817 | "text": "代码块", 1818 | "style": {}, 1819 | "location": { 1820 | "zoneId": "0", 1821 | "startIndex": 477, 1822 | "endIndex": 480 1823 | } 1824 | } 1825 | } 1826 | ], 1827 | "style": { 1828 | "headingLevel": 1 1829 | }, 1830 | "location": { 1831 | "zoneId": "0", 1832 | "startIndex": 476, 1833 | "endIndex": 480 1834 | }, 1835 | "lineId": "YXUEDz" 1836 | } 1837 | }, 1838 | { 1839 | "type": "code", 1840 | "code": { 1841 | "language": "Go", 1842 | "location": { 1843 | "zoneId": "0", 1844 | "startIndex": 481, 1845 | "endIndex": 482 1846 | }, 1847 | "zoneId": "kmeduldfp7", 1848 | "body": { 1849 | "blocks": [ 1850 | { 1851 | "type": "paragraph", 1852 | "paragraph": { 1853 | "elements": [ 1854 | { 1855 | "type": "textRun", 1856 | "textRun": { 1857 | "text": "func f() {", 1858 | "style": {}, 1859 | "location": { 1860 | "zoneId": "kmeduldfp7", 1861 | "startIndex": 0, 1862 | "endIndex": 10 1863 | } 1864 | } 1865 | } 1866 | ], 1867 | "location": { 1868 | "zoneId": "kmeduldfp7", 1869 | "startIndex": 0, 1870 | "endIndex": 10 1871 | }, 1872 | "lineId": "mgPCAK" 1873 | } 1874 | }, 1875 | { 1876 | "type": "paragraph", 1877 | "paragraph": { 1878 | "elements": [ 1879 | { 1880 | "type": "textRun", 1881 | "textRun": { 1882 | "text": "// do sth", 1883 | "style": {}, 1884 | "location": { 1885 | "zoneId": "kmeduldfp7", 1886 | "startIndex": 12, 1887 | "endIndex": 21 1888 | } 1889 | } 1890 | } 1891 | ], 1892 | "style": {}, 1893 | "location": { 1894 | "zoneId": "kmeduldfp7", 1895 | "startIndex": 11, 1896 | "endIndex": 21 1897 | }, 1898 | "lineId": "OVqoih" 1899 | } 1900 | }, 1901 | { 1902 | "type": "paragraph", 1903 | "paragraph": { 1904 | "elements": [ 1905 | { 1906 | "type": "textRun", 1907 | "textRun": { 1908 | "text": "}", 1909 | "style": {}, 1910 | "location": { 1911 | "zoneId": "kmeduldfp7", 1912 | "startIndex": 23, 1913 | "endIndex": 24 1914 | } 1915 | } 1916 | } 1917 | ], 1918 | "style": {}, 1919 | "location": { 1920 | "zoneId": "kmeduldfp7", 1921 | "startIndex": 22, 1922 | "endIndex": 24 1923 | }, 1924 | "lineId": "UmeYix" 1925 | } 1926 | } 1927 | ] 1928 | } 1929 | } 1930 | }, 1931 | { 1932 | "type": "paragraph", 1933 | "paragraph": { 1934 | "elements": [ 1935 | { 1936 | "type": "textRun", 1937 | "textRun": { 1938 | "text": "图片", 1939 | "style": {}, 1940 | "location": { 1941 | "zoneId": "0", 1942 | "startIndex": 484, 1943 | "endIndex": 486 1944 | } 1945 | } 1946 | } 1947 | ], 1948 | "style": { 1949 | "headingLevel": 1 1950 | }, 1951 | "location": { 1952 | "zoneId": "0", 1953 | "startIndex": 483, 1954 | "endIndex": 486 1955 | }, 1956 | "lineId": "GDaiFX" 1957 | } 1958 | }, 1959 | { 1960 | "type": "paragraph", 1961 | "paragraph": { 1962 | "elements": [ 1963 | { 1964 | "type": "textRun", 1965 | "textRun": { 1966 | "text": "一个图片", 1967 | "style": {}, 1968 | "location": { 1969 | "zoneId": "0", 1970 | "startIndex": 488, 1971 | "endIndex": 492 1972 | } 1973 | } 1974 | } 1975 | ], 1976 | "style": { 1977 | "headingLevel": 2 1978 | }, 1979 | "location": { 1980 | "zoneId": "0", 1981 | "startIndex": 487, 1982 | "endIndex": 492 1983 | }, 1984 | "lineId": "4s7vmw" 1985 | } 1986 | }, 1987 | { 1988 | "type": "gallery", 1989 | "gallery": { 1990 | "galleryStyle": {}, 1991 | "imageList": [ 1992 | { 1993 | "fileToken": "boxcnyAEhNeanmSz2XhcK7ata0t", 1994 | "width": 1536, 1995 | "height": 322 1996 | } 1997 | ], 1998 | "location": { 1999 | "zoneId": "0", 2000 | "startIndex": 493, 2001 | "endIndex": 495 2002 | } 2003 | } 2004 | }, 2005 | { 2006 | "type": "paragraph", 2007 | "paragraph": { 2008 | "elements": [ 2009 | { 2010 | "type": "textRun", 2011 | "textRun": { 2012 | "text": "并排图片", 2013 | "style": {}, 2014 | "location": { 2015 | "zoneId": "0", 2016 | "startIndex": 497, 2017 | "endIndex": 501 2018 | } 2019 | } 2020 | } 2021 | ], 2022 | "style": { 2023 | "headingLevel": 2 2024 | }, 2025 | "location": { 2026 | "zoneId": "0", 2027 | "startIndex": 496, 2028 | "endIndex": 501 2029 | }, 2030 | "lineId": "q69lzO" 2031 | } 2032 | }, 2033 | { 2034 | "type": "gallery", 2035 | "gallery": { 2036 | "galleryStyle": {}, 2037 | "imageList": [ 2038 | { 2039 | "fileToken": "boxcnx060XAN4NUm2doWRuGToWr", 2040 | "width": 332, 2041 | "height": 452 2042 | }, 2043 | { 2044 | "fileToken": "boxcniB7OYCR0mmRx0kBAcfbZmc", 2045 | "width": 392, 2046 | "height": 452 2047 | } 2048 | ], 2049 | "location": { 2050 | "zoneId": "0", 2051 | "startIndex": 502, 2052 | "endIndex": 505 2053 | } 2054 | } 2055 | }, 2056 | { 2057 | "type": "paragraph", 2058 | "paragraph": { 2059 | "elements": [], 2060 | "location": { 2061 | "zoneId": "0", 2062 | "startIndex": 506, 2063 | "endIndex": 506 2064 | }, 2065 | "lineId": "F1PKvG" 2066 | } 2067 | }, 2068 | { 2069 | "type": "paragraph", 2070 | "paragraph": { 2071 | "elements": [ 2072 | { 2073 | "type": "textRun", 2074 | "textRun": { 2075 | "text": "表格", 2076 | "style": {}, 2077 | "location": { 2078 | "zoneId": "0", 2079 | "startIndex": 508, 2080 | "endIndex": 510 2081 | } 2082 | } 2083 | } 2084 | ], 2085 | "style": { 2086 | "headingLevel": 1 2087 | }, 2088 | "location": { 2089 | "zoneId": "0", 2090 | "startIndex": 507, 2091 | "endIndex": 510 2092 | }, 2093 | "lineId": "BXyd1I" 2094 | } 2095 | }, 2096 | { 2097 | "type": "table", 2098 | "table": { 2099 | "tableId": "rs8vji1tokd8n9bl42jcndj0mmkjqsmsku-cs2j1enfcdj297uqvb6lq56qc5qoiasmb4", 2100 | "rowSize": 2, 2101 | "columnSize": 3, 2102 | "tableRows": [ 2103 | { 2104 | "rowIndex": 0, 2105 | "tableCells": [ 2106 | { 2107 | "zoneId": "xr1piaaher33bi4ad95vbvp508svs5cwb7vxc18mdhniulp2dj2zvb984e5dju8aytf4pm", 2108 | "columnIndex": 0, 2109 | "body": { 2110 | "blocks": [ 2111 | { 2112 | "type": "paragraph", 2113 | "paragraph": { 2114 | "elements": [ 2115 | { 2116 | "type": "textRun", 2117 | "textRun": { 2118 | "text": "x1.y1", 2119 | "style": {}, 2120 | "location": { 2121 | "zoneId": "xr1piaaher33bi4ad95vbvp508svs5cwb7vxc18mdhniulp2dj2zvb984e5dju8aytf4pm", 2122 | "startIndex": 0, 2123 | "endIndex": 5 2124 | } 2125 | } 2126 | } 2127 | ], 2128 | "location": { 2129 | "zoneId": "xr1piaaher33bi4ad95vbvp508svs5cwb7vxc18mdhniulp2dj2zvb984e5dju8aytf4pm", 2130 | "startIndex": 0, 2131 | "endIndex": 5 2132 | } 2133 | } 2134 | } 2135 | ] 2136 | } 2137 | }, 2138 | { 2139 | "zoneId": "xr1piaaher33bi4ad95vbvp508svs5cwb7vxc1ruer47l0w0znahmby2vf82fs025qqrh1", 2140 | "columnIndex": 1, 2141 | "body": { 2142 | "blocks": [ 2143 | { 2144 | "type": "paragraph", 2145 | "paragraph": { 2146 | "elements": [ 2147 | { 2148 | "type": "textRun", 2149 | "textRun": { 2150 | "text": "x2.y1", 2151 | "style": {}, 2152 | "location": { 2153 | "zoneId": "xr1piaaher33bi4ad95vbvp508svs5cwb7vxc1ruer47l0w0znahmby2vf82fs025qqrh1", 2154 | "startIndex": 0, 2155 | "endIndex": 5 2156 | } 2157 | } 2158 | } 2159 | ], 2160 | "location": { 2161 | "zoneId": "xr1piaaher33bi4ad95vbvp508svs5cwb7vxc1ruer47l0w0znahmby2vf82fs025qqrh1", 2162 | "startIndex": 0, 2163 | "endIndex": 5 2164 | }, 2165 | "lineId": "PqqSHc" 2166 | } 2167 | } 2168 | ] 2169 | } 2170 | }, 2171 | { 2172 | "zoneId": "xr1piaaher33bi4ad95vbvp508svs5cwb7vxc1k615ppodh0mnjeqcqwvzgq2tlyqfefhl", 2173 | "columnIndex": 2, 2174 | "body": { 2175 | "blocks": [ 2176 | { 2177 | "type": "paragraph", 2178 | "paragraph": { 2179 | "elements": [ 2180 | { 2181 | "type": "textRun", 2182 | "textRun": { 2183 | "text": "x3.y1", 2184 | "style": {}, 2185 | "location": { 2186 | "zoneId": "xr1piaaher33bi4ad95vbvp508svs5cwb7vxc1k615ppodh0mnjeqcqwvzgq2tlyqfefhl", 2187 | "startIndex": 0, 2188 | "endIndex": 5 2189 | } 2190 | } 2191 | } 2192 | ], 2193 | "location": { 2194 | "zoneId": "xr1piaaher33bi4ad95vbvp508svs5cwb7vxc1k615ppodh0mnjeqcqwvzgq2tlyqfefhl", 2195 | "startIndex": 0, 2196 | "endIndex": 5 2197 | }, 2198 | "lineId": "w7uf6j" 2199 | } 2200 | } 2201 | ] 2202 | } 2203 | } 2204 | ] 2205 | }, 2206 | { 2207 | "rowIndex": 1, 2208 | "tableCells": [ 2209 | { 2210 | "zoneId": "xr1ipuesurh0nzgi1j88te8z3uen6w9852uxc18mdhniulp2dj2zvb984e5dju8aytf4pm", 2211 | "columnIndex": 0, 2212 | "body": { 2213 | "blocks": [ 2214 | { 2215 | "type": "paragraph", 2216 | "paragraph": { 2217 | "elements": [ 2218 | { 2219 | "type": "textRun", 2220 | "textRun": { 2221 | "text": "x1.y2", 2222 | "style": {}, 2223 | "location": { 2224 | "zoneId": "xr1ipuesurh0nzgi1j88te8z3uen6w9852uxc18mdhniulp2dj2zvb984e5dju8aytf4pm", 2225 | "startIndex": 0, 2226 | "endIndex": 5 2227 | } 2228 | } 2229 | } 2230 | ], 2231 | "location": { 2232 | "zoneId": "xr1ipuesurh0nzgi1j88te8z3uen6w9852uxc18mdhniulp2dj2zvb984e5dju8aytf4pm", 2233 | "startIndex": 0, 2234 | "endIndex": 5 2235 | }, 2236 | "lineId": "90XYiS" 2237 | } 2238 | } 2239 | ] 2240 | } 2241 | }, 2242 | { 2243 | "zoneId": "xr1ipuesurh0nzgi1j88te8z3uen6w9852uxc1ruer47l0w0znahmby2vf82fs025qqrh1", 2244 | "columnIndex": 1, 2245 | "body": { 2246 | "blocks": [ 2247 | { 2248 | "type": "paragraph", 2249 | "paragraph": { 2250 | "elements": [ 2251 | { 2252 | "type": "textRun", 2253 | "textRun": { 2254 | "text": "x2.y2", 2255 | "style": {}, 2256 | "location": { 2257 | "zoneId": "xr1ipuesurh0nzgi1j88te8z3uen6w9852uxc1ruer47l0w0znahmby2vf82fs025qqrh1", 2258 | "startIndex": 0, 2259 | "endIndex": 5 2260 | } 2261 | } 2262 | } 2263 | ], 2264 | "location": { 2265 | "zoneId": "xr1ipuesurh0nzgi1j88te8z3uen6w9852uxc1ruer47l0w0znahmby2vf82fs025qqrh1", 2266 | "startIndex": 0, 2267 | "endIndex": 5 2268 | }, 2269 | "lineId": "lb3jJb" 2270 | } 2271 | } 2272 | ] 2273 | } 2274 | }, 2275 | { 2276 | "zoneId": "xr1ipuesurh0nzgi1j88te8z3uen6w9852uxc1k615ppodh0mnjeqcqwvzgq2tlyqfefhl", 2277 | "columnIndex": 2, 2278 | "body": { 2279 | "blocks": [ 2280 | { 2281 | "type": "paragraph", 2282 | "paragraph": { 2283 | "elements": [ 2284 | { 2285 | "type": "textRun", 2286 | "textRun": { 2287 | "text": "x3.y2", 2288 | "style": {}, 2289 | "location": { 2290 | "zoneId": "xr1ipuesurh0nzgi1j88te8z3uen6w9852uxc1k615ppodh0mnjeqcqwvzgq2tlyqfefhl", 2291 | "startIndex": 0, 2292 | "endIndex": 5 2293 | } 2294 | } 2295 | } 2296 | ], 2297 | "location": { 2298 | "zoneId": "xr1ipuesurh0nzgi1j88te8z3uen6w9852uxc1k615ppodh0mnjeqcqwvzgq2tlyqfefhl", 2299 | "startIndex": 0, 2300 | "endIndex": 5 2301 | }, 2302 | "lineId": "cWnsQz" 2303 | } 2304 | } 2305 | ] 2306 | } 2307 | } 2308 | ] 2309 | } 2310 | ], 2311 | "tableStyle": { 2312 | "tableColumnProperties": [ 2313 | { 2314 | "width": 100 2315 | }, 2316 | { 2317 | "width": 100 2318 | }, 2319 | { 2320 | "width": 100 2321 | } 2322 | ] 2323 | }, 2324 | "mergedCells": [], 2325 | "location": { 2326 | "zoneId": "0", 2327 | "startIndex": 511, 2328 | "endIndex": 513 2329 | } 2330 | } 2331 | }, 2332 | { 2333 | "type": "paragraph", 2334 | "paragraph": { 2335 | "elements": [ 2336 | { 2337 | "type": "textRun", 2338 | "textRun": { 2339 | "text": "电子表格", 2340 | "style": {}, 2341 | "location": { 2342 | "zoneId": "0", 2343 | "startIndex": 515, 2344 | "endIndex": 519 2345 | } 2346 | } 2347 | } 2348 | ], 2349 | "style": { 2350 | "headingLevel": 1 2351 | }, 2352 | "location": { 2353 | "zoneId": "0", 2354 | "startIndex": 514, 2355 | "endIndex": 519 2356 | }, 2357 | "lineId": "4Jz3RQ" 2358 | } 2359 | }, 2360 | { 2361 | "type": "sheet", 2362 | "sheet": { 2363 | "token": "shtcnVZBJ1F05uW16LwcibZDJdf_8OPm5F", 2364 | "location": { 2365 | "zoneId": "0", 2366 | "startIndex": 520, 2367 | "endIndex": 522 2368 | } 2369 | } 2370 | }, 2371 | { 2372 | "type": "paragraph", 2373 | "paragraph": { 2374 | "elements": [ 2375 | { 2376 | "type": "textRun", 2377 | "textRun": { 2378 | "text": "链接", 2379 | "style": {}, 2380 | "location": { 2381 | "zoneId": "0", 2382 | "startIndex": 524, 2383 | "endIndex": 526 2384 | } 2385 | } 2386 | } 2387 | ], 2388 | "style": { 2389 | "headingLevel": 1 2390 | }, 2391 | "location": { 2392 | "zoneId": "0", 2393 | "startIndex": 523, 2394 | "endIndex": 526 2395 | }, 2396 | "lineId": "XHyVHE" 2397 | } 2398 | }, 2399 | { 2400 | "type": "paragraph", 2401 | "paragraph": { 2402 | "elements": [ 2403 | { 2404 | "type": "textRun", 2405 | "textRun": { 2406 | "text": "链接文本", 2407 | "style": { 2408 | "link": { 2409 | "url": "https%3A%2F%2Fply.readthedocs.io%2Fen%2Flatest%2Fply.html" 2410 | } 2411 | }, 2412 | "location": { 2413 | "zoneId": "0", 2414 | "startIndex": 528, 2415 | "endIndex": 532 2416 | } 2417 | } 2418 | } 2419 | ], 2420 | "style": {}, 2421 | "location": { 2422 | "zoneId": "0", 2423 | "startIndex": 527, 2424 | "endIndex": 532 2425 | }, 2426 | "lineId": "3yjsF6" 2427 | } 2428 | }, 2429 | { 2430 | "type": "paragraph", 2431 | "paragraph": { 2432 | "elements": [ 2433 | { 2434 | "type": "textRun", 2435 | "textRun": { 2436 | "text": "网页卡片", 2437 | "style": {}, 2438 | "location": { 2439 | "zoneId": "0", 2440 | "startIndex": 534, 2441 | "endIndex": 538 2442 | } 2443 | } 2444 | } 2445 | ], 2446 | "style": { 2447 | "headingLevel": 1 2448 | }, 2449 | "location": { 2450 | "zoneId": "0", 2451 | "startIndex": 533, 2452 | "endIndex": 538 2453 | }, 2454 | "lineId": "LyC1CF" 2455 | } 2456 | }, 2457 | { 2458 | "type": "undefinedBlock", 2459 | "undefinedBlock": { 2460 | "location": { 2461 | "zoneId": "0", 2462 | "startIndex": 539, 2463 | "endIndex": 541 2464 | } 2465 | } 2466 | }, 2467 | { 2468 | "type": "paragraph", 2469 | "paragraph": { 2470 | "elements": [ 2471 | { 2472 | "type": "textRun", 2473 | "textRun": { 2474 | "text": "云文档", 2475 | "style": {}, 2476 | "location": { 2477 | "zoneId": "0", 2478 | "startIndex": 543, 2479 | "endIndex": 546 2480 | } 2481 | } 2482 | } 2483 | ], 2484 | "style": { 2485 | "headingLevel": 1 2486 | }, 2487 | "location": { 2488 | "zoneId": "0", 2489 | "startIndex": 542, 2490 | "endIndex": 546 2491 | }, 2492 | "lineId": "xWRS5q" 2493 | } 2494 | }, 2495 | { 2496 | "type": "paragraph", 2497 | "paragraph": { 2498 | "elements": [ 2499 | { 2500 | "type": "docsLink", 2501 | "docsLink": { 2502 | "url": "https://rs6qnacjws.feishu.cn/docs/doccnKOgFFoPz5Z1OZ5wU9H7sdf", 2503 | "location": { 2504 | "zoneId": "0", 2505 | "startIndex": 547, 2506 | "endIndex": 559 2507 | } 2508 | } 2509 | } 2510 | ], 2511 | "location": { 2512 | "zoneId": "0", 2513 | "startIndex": 547, 2514 | "endIndex": 559 2515 | }, 2516 | "lineId": "T6caa5" 2517 | } 2518 | }, 2519 | { 2520 | "type": "paragraph", 2521 | "paragraph": { 2522 | "elements": [ 2523 | { 2524 | "type": "textRun", 2525 | "textRun": { 2526 | "text": "群名片", 2527 | "style": {}, 2528 | "location": { 2529 | "zoneId": "0", 2530 | "startIndex": 561, 2531 | "endIndex": 564 2532 | } 2533 | } 2534 | } 2535 | ], 2536 | "style": { 2537 | "headingLevel": 1 2538 | }, 2539 | "location": { 2540 | "zoneId": "0", 2541 | "startIndex": 560, 2542 | "endIndex": 564 2543 | }, 2544 | "lineId": "QGxelY" 2545 | } 2546 | }, 2547 | { 2548 | "type": "chatGroup", 2549 | "chatGroup": { 2550 | "openChatId": "oc_e5dc4d726035aff7317c168440ed5b5b", 2551 | "location": { 2552 | "zoneId": "0", 2553 | "startIndex": 565, 2554 | "endIndex": 567 2555 | } 2556 | } 2557 | }, 2558 | { 2559 | "type": "paragraph", 2560 | "paragraph": { 2561 | "elements": [ 2562 | { 2563 | "type": "textRun", 2564 | "textRun": { 2565 | "text": "文件", 2566 | "style": {}, 2567 | "location": { 2568 | "zoneId": "0", 2569 | "startIndex": 569, 2570 | "endIndex": 571 2571 | } 2572 | } 2573 | } 2574 | ], 2575 | "style": { 2576 | "headingLevel": 1 2577 | }, 2578 | "location": { 2579 | "zoneId": "0", 2580 | "startIndex": 568, 2581 | "endIndex": 571 2582 | }, 2583 | "lineId": "VHuRJX" 2584 | } 2585 | }, 2586 | { 2587 | "type": "file", 2588 | "file": { 2589 | "fileToken": "boxcnBne2oNxLjcnSTFURxU0czv", 2590 | "viewType": "card", 2591 | "fileName": "pending.png", 2592 | "location": { 2593 | "zoneId": "0", 2594 | "startIndex": 572, 2595 | "endIndex": 574 2596 | } 2597 | } 2598 | }, 2599 | { 2600 | "type": "paragraph", 2601 | "paragraph": { 2602 | "elements": [], 2603 | "location": { 2604 | "zoneId": "0", 2605 | "startIndex": 575, 2606 | "endIndex": 575 2607 | }, 2608 | "lineId": "Xq8AiE" 2609 | } 2610 | } 2611 | ] 2612 | } 2613 | } 2614 | --------------------------------------------------------------------------------