Làm việc với nhận xét và đề xuất

Google Tài liệu cho phép cộng tác viên cộng tác bằng cách viết nhận xét và đưa ra đề xuất. Các đề xuất này hoạt động như nội dung chỉnh sửa bị hoãn lại và đang chờ phê duyệt.

Bạn có thể sử dụng API này để xem các thay đổi được đề xuất ngay trong văn bản của tài liệu. Trong Bản dùng thử cho nhà phát triển, bạn cũng có thể đọc, tạo, trả lời, cập nhật hoặc xoá các chuỗi bình luận và đề xuất theo cách lập trình.

Khi bạn sử dụng phương thức documents.get để tìm nạp nội dung tài liệu, nội dung đó có thể bao gồm cả những đề xuất chưa được giải quyết. Để kiểm soát cách documents.get biểu thị các đề xuất, hãy sử dụng tham số SuggestionsViewMode không bắt buộc. Bạn có thể sử dụng các điều kiện lọc sau đây với tham số này:

  • Nhận nội dung bằng SUGGESTIONS_INLINE, để văn bản đang chờ xoá hoặc chèn xuất hiện trong tài liệu.
  • Xem trước nội dung khi tất cả đề xuất đã được chấp nhận.
  • Xem trước nội dung mà không có đề xuất, với tất cả đề xuất đều bị từ chối.

Nếu bạn không cung cấp SuggestionsViewMode, Google Docs API sẽ sử dụng chế độ cài đặt mặc định phù hợp với đặc quyền của người dùng hiện tại.

Đề xuất và chỉ mục

Một lý do khiến SuggestionsViewMode trở nên quan trọng là các chỉ mục trong phản hồi có thể thay đổi tuỳ thuộc vào việc có đề xuất hay không, như minh hoạ bên dưới.

Nội dung có đề xuất Nội dung không có đề xuất
{
 "tabs": [
  {
   "documentTab": {
    "body": {
     "content": [
      {
       "startIndex": 1,
       "endIndex": 31,
       "paragraph": {
        "elements": [
         {
          "startIndex": 1,
          "endIndex": 31,
          "textRun": {
           "content": "Text preceding the suggestion\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      },
      {
       "startIndex": 31,
       "endIndex": 51,
       "paragraph": {
        "elements": [
         {
          "startIndex": 31,
          "endIndex": 50,
          "textRun": {
           "content": "Suggested insertion",
           "suggestedInsertionIds": [
            "suggest.vcti8ewm4mww"
           ],
           "textStyle": {}
          }
         },
         {
          "startIndex": 50,
          "endIndex": 51,
          "textRun": {
           "content": "\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      },
      {
       "startIndex": 51,
       "endIndex": 81,
       "paragraph": {
        "elements": [
         {
          "startIndex": 51,
          "endIndex": 81,
          "textRun": {
           "content": "Text following the suggestion\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      }
     ]
    }
   }
  }
 ]
},

{
 "tabs": [
  {
   "documentTab": {
    "body": {
     "content": [
      {
       "startIndex": 1,
       "endIndex": 31,
       "paragraph": {
        "elements": [
         {
          "startIndex": 1,
          "endIndex": 31,
          "textRun": {
           "content": "Text preceding the suggestion\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      },
      {
       "startIndex": 31,
       "endIndex": 32,
       "paragraph": {
        "elements": [
         {
          "startIndex": 31,
          "endIndex": 32,
          "textRun": {
           "content": "\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      },
      {
       "startIndex": 32,
       "endIndex": 62,
       "paragraph": {
        "elements": [
         {
          "startIndex": 32,
          "endIndex": 62,
          "textRun": {
           "content": "Text following the suggestion\n",
           "textStyle": {}
          }
         }
        ],
        "paragraphStyle": {
         "namedStyleType": "NORMAL_TEXT",
         "direction": "LEFT_TO_RIGHT"
        }
       }
      }
     ]
    }
   }
  }
 ]
},

Trong phản hồi ở trên, đoạn văn có chứa dòng "Văn bản sau đề xuất" cho thấy sự khác biệt khi sử dụng SuggestionsViewMode. Khi giá trị được đặt thành SUGGESTIONS_INLINE, startIndex của ParagraphElement bắt đầu ở 51 và endIndex dừng ở 81. Nếu không có đề xuất, startIndexendIndex sẽ nằm trong khoảng từ 32 đến 62.

Xem nội dung mà không có đề xuất

Mẫu mã sau đây cho thấy cách nhận một tài liệu dưới dạng bản xem trước với tất cả các đề xuất bị từ chối (nếu có) bằng cách đặt tham số SuggestionsViewMode thành PREVIEW_WITHOUT_SUGGESTIONS.

Java

final string SUGGEST_MODE = "PREVIEW_WITHOUT_SUGGESTIONS";
Document doc =
    service
        .documents()
        .get(DOCUMENT_ID)
        .setIncludeTabsContent(true)
        .setSuggestionsViewMode(SUGGEST_MODE)
        .execute();

Python

SUGGEST_MODE = "PREVIEW_WITHOUT_SUGGESTIONS"
result = (
  service.documents()
  .get(
      documentId=DOCUMENT_ID,
      includeTabsContent=True,
      suggestionsViewMode=SUGGEST_MODE,
  )
  .execute()
)

Việc bỏ qua tham số SuggestionsViewMode tương đương với việc cung cấp DEFAULT_FOR_CURRENT_ACCESS làm giá trị tham số.

Đề xuất về phong cách

Tài liệu cũng có thể có đề xuất về kiểu. Đây là những thay đổi được đề xuất về định dạng và cách trình bày, chứ không phải thay đổi về nội dung.

Không giống như việc chèn hoặc xoá văn bản, những thay đổi này không bù đắp chỉ mục – mặc dù chúng có thể chia TextRun thành các phần nhỏ hơn – mà chỉ thêm chú thích về thay đổi kiểu được đề xuất.

Một chú thích như vậy là SuggestedTextStyle, bao gồm 2 phần:

  • textStyle mô tả cách văn bản được tạo kiểu sau khi thay đổi được đề xuất, nhưng không cho biết nội dung đã thay đổi.

  • textStyleSuggestionState, cho biết cách đề xuất thay đổi các trường của textStyle.

Bạn có thể thấy điều này trong đoạn trích thẻ tài liệu sau đây, bao gồm cả một thay đổi về kiểu được đề xuất:

[01] "paragraph": {
[02]    "elements": [
[03]        {
[04]            "endIndex": 106,
[05]            "startIndex": 82,
[06]            "textRun": {
[07]                "content": "Some text that does not ",
[08]                "textStyle": {}
[09]            }
[10]        },
[11]        {
[12]            "endIndex": 115,
[13]            "startIndex": 106,
[14]            "textRun": {
[15]                "content": "initially",
[16]                "suggestedTextStyleChanges": {
[17]                    "suggest.xymysbs9zldp": {
[18]                        "textStyle": {
[19]                            "backgroundColor": {},
[20]                            "baselineOffset": "NONE",
[21]                            "bold": true,
[22]                            "fontSize": {
[23]                                "magnitude": 11,
[24]                                "unit": "PT"
[25]                            },
[26]                            "foregroundColor": {
[27]                                "color": {
[28]                                    "rgbColor": {}
[29]                                }
[30]                            },
[31]                            "italic": false,
[32]                            "smallCaps": false,
[33]                            "strikethrough": false,
[34]                            "underline": false
[35]                        },
[36]                        "textStyleSuggestionState": {
[37]                            "boldSuggested": true,
[38]                            "weightedFontFamilySuggested": true
[39]                        }
[40]                    }
[41]                },
[42]                "textStyle": {
[43]                    "italic": true
[44]                }
[45]            }
[46]        },
[47]        {
[48]            "endIndex": 143,
[49]            "startIndex": 115,
[50]            "textRun": {
[51]                "content": " contain any boldface text.\n",
[52]                "textStyle": {}
[53]            }
[54]        }
[55]    ],
[56]    "paragraphStyle": {
[57]        "direction": "LEFT_TO_RIGHT",
[58]        "namedStyleType": "NORMAL_TEXT"
[59]    }
[60] }

Trong mẫu ở trên, đoạn văn bao gồm 3 đoạn văn bản, bắt đầu từ dòng 6, 14 và 50. Kiểm tra chuỗi văn bản ở giữa:

  • Dòng 16: Có một đối tượng suggestedTextStyleChanges.
  • Dòng 18: textStyle chỉ định nhiều định dạng.
  • Dòng 36: textStyleSuggestionState cho biết rằng chỉ phần in đậm của quy cách này là đề xuất.
  • Dòng 42: Kiểu chữ nghiêng của đoạn văn bản này là một phần của tài liệu hiện tại (và không bị ảnh hưởng bởi đề xuất).

Chỉ những tính năng kiểu được đặt thành true trong textStyleSuggestionState mới thuộc đề xuất.

Tạo và quản lý bình luận

Bạn có thể thêm nhận xét và câu trả lời, chỉnh sửa nhận xét và xoá nhận xét hoặc câu trả lời theo cách lập trình bằng phương thức documents.batchUpdate.

Khi thực hiện các bản cập nhật hàng loạt liên quan đến bình luận hoặc đề xuất, bạn nên theo dõi để phát hiện các lỗi có thể xảy ra. Để biết thêm thông tin, hãy xem bài viết Trạng thái cập nhật của bình luận và đề xuất.

Chèn nhận xét

Để chèn một chuỗi bình luận, hãy dùng đối tượng InsertCommentRequest. Bạn phải cung cấp nội dung văn bản của bình luận và vị trí của điểm đánh dấu (chẳng hạn như một dải ô) nơi bình luận được đính kèm.

Ví dụ về JSON sau đây sẽ thêm một chuỗi bình luận chưa được chỉ định vào dải ô được chỉ định:

{
  "requests": [
    {
      "insertComment": {
        "content": "This is a comment added via the API.",
        "range": {
          "startIndex": 10,
          "endIndex": 25
        }
      }
    }
  ]
}

Bạn có thể chỉ định một bình luận cho một người dùng cụ thể bằng cách cung cấp email của họ trong trường assigneeEmailAddress:

{
  "requests": [
    {
      "insertComment": {
        "content": "Please review this paragraph.",
        "assigneeEmailAddress": "user@example.com",
        "range": {
          "startIndex": 10,
          "endIndex": 25
        }
      }
    }
  ]
}

Thêm câu trả lời hoặc thực hiện hành động

Để trả lời một chuỗi bình luận hoặc đề xuất, hoặc để giải quyết hoặc mở lại một chuỗi, hãy sử dụng biểu tượng AddCommentReplyRequest.

Phản hồi được biểu thị bằng một đối tượng Post. Đối tượng Post chứa câu trả lời content và có thể tuỳ ý chỉ định commentAction (để RESOLVE hoặc REOPEN chuỗi).

Bạn cũng có thể chỉ định một assigneeEmail mới trong đối tượng Post để chỉ định lại một chuỗi bình luận.

Mẫu sau đây trả lời một chuỗi bình luận hiện có:

{
  "requests": [
    {
      "addCommentReply": {
        "commentId": "comment_thread_id",
        "post": {
          "content": "Replying to the comment thread."
        }
      }
    }
  ]
}

Mẫu sau đây giải quyết một chuỗi bình luận, không yêu cầu nội dung:

{
  "requests": [
    {
      "addCommentReply": {
        "commentId": "comment_thread_id",
        "post": {
          "commentAction": "RESOLVE"
        }
      }
    }
  ]
}

Mẫu JSON sau đây cho thấy cách chỉ định lại một chuỗi bình luận:

{
  "requests": [
    {
      "addCommentReply": {
        "commentId": "comment_thread_id",
        "post": {
          "content": "Replying to the comment thread.",
          "assigneeEmail": "user@example.com"
        }
      }
    }
  ]
}

Chỉnh sửa bài đăng

Để chỉnh sửa nội dung văn bản của bài đăng mà bạn đã tạo, hãy dùng biểu tượng UpdateCommentPostRequest. Bạn phải chỉ định mã nhận dạng luồng (commentId hoặc suggestionId), postId của bài đăng mà bạn muốn chỉnh sửa và content văn bản thuần tuý mới.

Xin lưu ý rằng bạn không thể chỉnh sửa bài đăng đầu tiên của một chuỗi đề xuất (vì những bài đăng đó được tạo bằng chế độ đề xuất chỉnh sửa).

{
  "requests": [
    {
      "updateCommentPost": {
        "commentId": "comment_thread_id",
        "postId": "post_id",
        "content": "This is the updated comment text."
      }
    }
  ]
}

Xoá bình luận và câu trả lời

  • Xoá một chuỗi bình luận: Để xoá toàn bộ một chuỗi bình luận, hãy dùng biểu tượng DeleteCommentRequest. Bạn chỉ có thể xoá một chuỗi bình luận nếu bạn là tác giả của bài đăng đầu tiên trong chuỗi đó.
  • Xoá câu trả lời: Để xoá một bài đăng trả lời cụ thể, hãy sử dụng DeleteCommentReplyRequest. Bạn chỉ có thể xoá những câu trả lời do chính mình viết. Bạn không thể xoá bài đăng trả lời có chứa hành động hoặc người được giao.

Mẫu sau đây xoá một chuỗi bình luận:

{
  "requests": [
    {
      "deleteComment": {
        "commentId": "comment_thread_id"
      }
    }
  ]
}

Viết đề xuất và quản lý chuỗi đề xuất

Bạn có thể viết nội dung chỉnh sửa dưới dạng đề xuất thay vì chỉnh sửa trực tiếp, đồng thời chấp nhận, từ chối hoặc xoá các chuỗi đề xuất theo cách lập trình.

Khi thực hiện các bản cập nhật hàng loạt liên quan đến đề xuất, bạn nên theo dõi để tránh trường hợp thất bại một phần. Để biết thêm thông tin, hãy xem bài viết Trạng thái cập nhật của bình luận và đề xuất.

Tạo đề xuất bằng chế độ đề xuất

Để áp dụng nội dung chỉnh sửa dưới dạng đề xuất, hãy đặt trường writeMode của đối tượng WriteControl thành SUGGEST trong yêu cầu cập nhật theo lô. Tất cả nội dung cập nhật trong yêu cầu đều được xử lý dưới dạng đề xuất.

{
  "requests": [
    {
      "insertText": {
        "text": "suggested insertion text",
        "location": {
          "index": 1
        }
      }
    }
  ],
  "writeControl": {
    "writeMode": "SUGGEST"
  }
}

Các yêu cầu không được hỗ trợ ở chế độ đề xuất

Khi sử dụng WriteMode.SUGGEST, các loại yêu cầu sau đây không được hỗ trợ và sẽ trả về lỗi:

  • AddDocumentTab
  • CreateNamedRange
  • DeleteFooter
  • DeleteHeader
  • DeleteNamedRange
  • DeleteTab
  • UpdateDocumentTabProperties
  • UpdateTableColumnProperties

Ngoài ra, bạn không thể đề xuất thay đổi định dạng tài liệu hoặc chế độ cài đặt đầu trang/chân trang. Trong UpdateDocumentStyle, các loại kiểu sau đây không được hỗ trợ cho đề xuất:

  • documentFormat
  • useEvenPageHeaderFooter
  • useFirstPageHeaderFooter

Chấp nhận, từ chối hoặc xoá chuỗi đề xuất

Bạn có thể quản lý các chuỗi đề xuất bằng cách sử dụng các yêu cầu sau:

  • Chấp nhận đề xuất: Sử dụng AcceptSuggestionRequest để chấp nhận đề xuất. Bạn cần có quyền chỉnh sửa tài liệu để thực hiện việc này.
  • Từ chối đề xuất: Sử dụng biểu tượng RejectSuggestionRequest để từ chối đề xuất. Bạn cần có quyền chỉnh sửa đối với tài liệu hoặc là tác giả của đề xuất.
  • Xoá đề xuất: Sử dụng biểu tượng DeleteSuggestionRequest để xoá đề xuất. Bạn phải là tác giả của đề xuất để thực hiện việc này.

Mẫu sau đây chấp nhận một chuỗi đề xuất:

{
  "requests": [
    {
      "acceptSuggestion": {
        "suggestionId": "suggestion_thread_id"
      }
    }
  ]
}

Trạng thái cập nhật nhận xét và đề xuất

Những yêu cầu cần lưu chuỗi bình luận hoặc đề xuất (chẳng hạn như chèn bình luận, thêm câu trả lời hoặc đưa ra đề xuất) có thể gặp phải lỗi một phần. Trong những trường hợp này, các thay đổi về mô hình tài liệu (chẳng hạn như việc chèn hoặc xoá văn bản) có thể được cam kết thành công với mô hình Tài liệu, nhưng các nhận xét hoặc đề xuất liên quan có thể không lưu được.

Bạn có thể xác minh xem nội dung cập nhật về bình luận hoặc đề xuất có được áp dụng thành công hay không bằng cách kiểm tra trường commentUpdateState trong BatchUpdateDocumentResponse.

Các trạng thái sau đây được trả về trong CommentUpdateState:

  • NO_UPDATES_REQUESTED: Không có yêu cầu cập nhật bình luận hoặc đề xuất nào trong thao tác hàng loạt.
  • ALL_SAVED: Tất cả nội dung cập nhật được yêu cầu đối với bình luận hoặc đề xuất đều đã được áp dụng thành công.
  • ALL_FAILED_UNKNOWN_REASON: Tất cả nội dung cập nhật về nhận xét hoặc đề xuất được yêu cầu đều không lưu được, mặc dù có thể mô hình Tài liệu đã được thay đổi.