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 đóng vai trò là các nội dung chỉnh sửa bị trì hoãn và chờ phê duyệt.

Bạn có thể sử dụng API để 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 nhận xét và đề xuất theo phương thức 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ác đề xuất chưa được giải quyết. Để kiểm soát cách documents.get trình bày các đề xuất, hãy sử dụng tham số không bắt buộc SuggestionsViewMode. Bạn có thể sử dụng các điều kiện lọc sau đây với tham số này:

  • Tìm nạp 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.
  • Tìm nạp nội dung ở dạng bản xem trước với tất cả đề xuất được chấp nhận.
  • Tìm nạp nội dung ở dạng bản xem trước, không có đề xuất, với tất cả đề xuất bị từ chối.

Nếu bạn không cung cấp SuggestionsViewMode, API Google Tài liệu 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

SuggestionsViewMode quan trọng vì một lý do là các chỉ mục trong phản hồi có thể khác nhau 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ó dòng "Text following the suggestion" (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 từ 51 và endIndex dừng ở 81. Nếu không có đề xuất, thì startIndexendIndex sẽ nằm trong khoảng từ 32 đến 62.

Tìm nạp nội dung không có đề xuất

Mẫu mã một phần sau đây cho biết cách tìm nạp tài liệu ở dạng bản xem trước với tất 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ề phong cách. Đây là những thay đổi được đề xuất đối với định dạng và cách trình bày, thay vì thay đổi 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 các chỉ mục (mặc dù có thể chia TextRun thành các phần nhỏ hơn), mà chỉ thêm chú thích về thay đổi phong cách được đề xuất.

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

  • textStyle mô tả cách tạo kiểu cho văn bản 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 phần trích xuất thẻ tài liệu sau đây, bao gồm cả thay đổi về phong cách đượ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. Hãy xem xét đoạn 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 bạn biết rằng chỉ phần in đậm của thông số kỹ thuật này là đề xuất.
  • Dòng 42: Kiểu in 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 về phong cách được đặt thành true trong textStyleSuggestionState mới là một phần của đề xuất.

Tạo và quản lý nhận xét

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 phương thức 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 nhận xét hoặc đề xuất, bạn nên theo dõi để tránh trường hợp lỗ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 nhận xét và đề xuất.

Chèn nhận xét

Để chèn một chuỗi nhận xét, hãy sử dụng InsertCommentRequest đối tượng. Bạn phải cung cấp nội dung văn bản nhận xét và vị trí neo (chẳng hạn như một phạm vi) nơi nhận xét được đính kèm.

Ví dụ sau đây về JSON sẽ thêm một chuỗi nhận xét không được chỉ định vào phạm vi đã 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 nhận xét 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 nhận xét hoặc đề xuất, hoặc để giải quyết hoặc mở lại một chuỗi, hãy sử dụng AddCommentReplyRequest.

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

Mẫu sau đây trả lời một chuỗi nhận xét 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 nhận xét không yêu cầu nội dung:

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

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

Để chỉnh sửa nội dung văn bản của một bài đăng mà bạn đã tạo, hãy sử dụng UpdateCommentPostRequest. Bạn phải chỉ định mã chuỗi (là commentId hoặc suggestionId), postId của bài đăng 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 các nội dung chỉnh sửa ở chế độ đề xuất).

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

Xoá nhận xét và câu trả lời

  • Xoá một chuỗi nhận xét: Để xoá toàn bộ chuỗi nhận xét, hãy sử dụng DeleteCommentRequest. Bạn chỉ có thể xoá một chuỗi nhận xét 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 mà bạn đã tạo. Bạn không thể xoá các bài đăng trả lời có chứa hành động hoặc người được chỉ định.

Mẫu sau đây sẽ xoá một chuỗi nhận xét:

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

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

Bạn có thể viết các 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 phương thức 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 lỗ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 nhận xét và đề xuất.

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

Để áp dụng các 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 hàng loạt. 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 các thay đổi đối với định dạng tài liệu hoặc chế độ cài đặt đầu trang/chân trang. Trong UpdateDocumentStyle, các đề xuất không được hỗ trợ cho các loại phong cách sau:

  • 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á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 đối với tài liệu.
  • Từ chối đề xuất: Sử dụ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 DeleteSuggestionRequest để xoá đề xuất. Bạn cần là tác giả của đề xuất.

Mẫu sau đây sẽ 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

Các yêu cầu cần lưu chuỗi nhận xét hoặc đề xuất (chẳng hạn như chèn nhận xét, 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 đối với mô hình tài liệu (chẳng hạn như chèn hoặc xoá văn bản) có thể được cam kết thành công đối 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 các bản cập nhật nhận xét hoặc đề xuất đã được áp dụng thành công hay chưa 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ó bản cập nhật nhận xét hoặc đề xuất nào được yêu cầu trong thao tác hàng loạt.
  • ALL_SAVED: Tất cả bản cập nhật nhận xét hoặc đề xuất được yêu cầu đều được áp dụng thành công.
  • ALL_FAILED_UNKNOWN_REASON: Tất cả bản cập nhật nhận xét hoặc đề xuất được yêu cầu đều không lưu được, mặc dù các thay đổi đối với mô hình Tài liệu có thể đã được cam kết.