API

在SpreadJS中,您可以使用全面的API以编程方式管理线程注释。该API允许您创建、检索、更新和删除线程注释及其回复,以及管理它们的解决状态。

管理线程注释 线程注释提供了一系列API。您可以通过编程方式创建、管理和组织线程注释及回复。 创建线程注释 要在单元格上创建线程注释,请使用工作表的threadedComments管理器上的add方法。然后添加线程的第一个回复: 获取和删除线程注释 您可以使用get方法获取线程注释,并使用remove方法删除它: 管理已解决状态 您可以使用resolved方法将线程注释标记为已解决或未解决: 添加回复 使用add方法向线程注释添加回复。每个回复可以包含文本、提及和链接: 更新回复 使用set方法更新现有回复: 删除回复 使用remove方法删除特定回复: 用户管理 配置用户管理器 在使用线程注释之前,请使用用户查找和搜索函数配置UserManager: 设置当前用户 设置将创作新评论和回复的当前用户:
window.onload = function () { var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss")); initSpread(spread); }; // User IDs in GUID format var USER_IDS = { ALICE: "{715CFD19-2BB9-4B94-DE0C-08D0F9A019DB}", BOB: "{8A3E2F47-5C1D-4E8B-A9F2-3B7C6D8E9F01}", CAROL: "{C4D5E6F7-8A9B-0C1D-2E3F-4A5B6C7D8E9F}", DAVID: "{D1E2F3A4-B5C6-7D8E-9F0A-1B2C3D4E5F67}" }; var activeThreadedComment = null; var activeReplyIndex = null; function initSpread(spread) { // Configure UserManager first configureUserManager(); spread.suspendPaint(); var sheet = spread.getActiveSheet(); sheet.options.allowCellOverflow = true; // Create a sample data table createSampleTable(sheet); // Add threaded comments to demonstrate various APIs addThreadedComments(sheet); spread.resumePaint(); // Bind selection change event var spreadNS = GC.Spread.Sheets; spread.bind(spreadNS.Events.SelectionChanged, function (e, info) { var sheetTmp = info.sheet; var row = sheetTmp.getActiveRowIndex(); var col = sheetTmp.getActiveColumnIndex(); var threadedComment = sheetTmp.threadedComments.get(row, col); if (threadedComment) { _getElementById("commentTip").innerHTML = "Threaded Comment in Cell [ " + row + " : " + col + " ]"; activeThreadedComment = threadedComment; activeReplyIndex = null; loadReplies(); // Automatically load replies } else { _getElementById("commentTip").innerHTML = "No Threaded Comment"; activeThreadedComment = null; activeReplyIndex = null; clearReplies(); // Clear replies list } updateLabels(spread); }); // Bind button events bindButtonEvents(spread); } function configureUserManager() { // Mock user database with GUID-style IDs and avatars var users = [ { id: USER_IDS.ALICE, name: "Alice Johnson", email: "alice.johnson@company.com", avatar: { kind: "data", dataUrl: "data:image/png;base64,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" } }, { id: USER_IDS.BOB, name: "Bob Smith", email: "bob.smith@company.com", avatar: { kind: "data", dataUrl: "data:image/png;base64,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" } }, { id: USER_IDS.CAROL, name: "Carol Manager", email: "carol.manager@company.com", avatar: { kind: "data", dataUrl: "data:image/png;base64,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" } }, { id: USER_IDS.DAVID, name: "David Accountant", email: "david.accountant@company.com", avatar: { kind: "data", dataUrl: "data:image/png;base64,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" } } ]; GC.Spread.Common.UserManager.configure({ get: async (userId) => { if (userId === undefined) { return; } return new Promise((resolve) => { const user = users.find(u => u.id === userId); resolve(user); }); }, search: async (query) => { return new Promise((resolve) => { resolve(users.filter(u => u.name.toLowerCase().includes(query.toLowerCase()) || u.email.toLowerCase().includes(query.toLowerCase()) )); }); } }); // Set current user GC.Spread.Common.UserManager.current(USER_IDS.ALICE); } function addThreadedComments(sheet) { var threadedCommentManager = sheet.threadedComments; // Example 1: Simple threaded comment with one reply on Reserve var tc1 = threadedCommentManager.add(9, 2); tc1.add({ message: [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: "Please verify if 10% reserve is sufficient for this quarter." } ], authorId: USER_IDS.ALICE, createdAt: new Date() }); // Example 2: Threaded comment with multiple replies on Total Budget var tc2 = threadedCommentManager.add(10, 2); tc2.add({ message: [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: "The total budget looks reasonable." } ], authorId: USER_IDS.ALICE, createdAt: new Date(Date.now() - 86400000) // 1 day ago }); tc2.add({ message: [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: "Confirmed. Ready for approval." } ], authorId: USER_IDS.BOB, createdAt: new Date(Date.now() - 43200000) // 12 hours ago }); tc2.add({ message: [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: "Approved!" } ], authorId: USER_IDS.CAROL, createdAt: new Date() }); // Example 3: Resolved threaded comment on Operations var tc3 = threadedCommentManager.add(4, 2); tc3.add({ message: [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: "Should we increase the operations budget?" } ], authorId: USER_IDS.BOB, createdAt: new Date(Date.now() - 172800000) // 2 days ago }); tc3.add({ message: [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: "No, this amount aligns with our Q3 plans." } ], authorId: USER_IDS.ALICE, createdAt: new Date(Date.now() - 86400000) // 1 day ago }); // Mark this thread as resolved tc3.resolved(true); // Example 4: Comment with mention and link on Development variance var tc4 = threadedCommentManager.add(3, 4); tc4.add({ message: [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: "Hey " }, { type: GC.Spread.Sheets.ThreadedComments.ContentType.mention, userId: USER_IDS.DAVID }, { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: ", please review the budget variance in Development department: " }, { type: GC.Spread.Sheets.ThreadedComments.ContentType.link, href: "https://example.com/budget-policy", text: "Budget Policy" } ], authorId: USER_IDS.ALICE, createdAt: new Date() }); } function createSampleTable(sheet) { // Set column widths sheet.setColumnWidth(1, 150); sheet.setColumnWidth(2, 120); sheet.setColumnWidth(3, 100); sheet.setColumnWidth(4, 120); // Headers sheet.setValue(1, 1, "Department"); sheet.setValue(1, 2, "Q3 Budget"); sheet.setValue(1, 3, "Q3 Actual"); sheet.setValue(1, 4, "Variance"); sheet.getRange(1, 1, 1, 4).font("bold 12pt Arial"); // Department budget data sheet.setValue(2, 1, "Marketing"); sheet.setValue(2, 2, 15000); sheet.setValue(2, 3, 14200); sheet.getCell(2, 4).formula("=C3-D3"); sheet.setValue(3, 1, "Development"); sheet.setValue(3, 2, 25000); sheet.setValue(3, 3, 26800); sheet.getCell(3, 4).formula("=C4-D4"); sheet.setValue(4, 1, "Operations"); sheet.setValue(4, 2, 10000); sheet.setValue(4, 3, 9850); sheet.getCell(4, 4).formula("=C5-D5"); sheet.setValue(5, 1, "Sales"); sheet.setValue(5, 2, 18000); sheet.setValue(5, 3, 17500); sheet.getCell(5, 4).formula("=C6-D6"); sheet.setValue(6, 1, "HR"); sheet.setValue(6, 2, 8000); sheet.setValue(6, 3, 8200); sheet.getCell(6, 4).formula("=C7-D7"); sheet.setValue(7, 1, "IT Support"); sheet.setValue(7, 2, 12000); sheet.setValue(7, 3, 11600); sheet.getCell(7, 4).formula("=C8-D8"); // Subtotal row sheet.setValue(8, 1, "Subtotal"); sheet.getCell(8, 2).formula("=SUM(C3:C8)"); sheet.getCell(8, 3).formula("=SUM(D3:D8)"); sheet.getCell(8, 4).formula("=SUM(E3:E8)"); sheet.getRange(8, 1, 1, 4).font("bold 11pt Arial"); // Reserve calculation sheet.setValue(9, 1, "Reserve (10%)"); sheet.getCell(9, 2).formula("=C8*0.1"); sheet.setValue(9, 3, ""); sheet.setValue(9, 4, ""); sheet.getCell(9, 1).font("bold 11pt Arial"); sheet.getCell(9, 2).font("bold 11pt Arial"); sheet.getCell(9, 2).backColor("#FFEB9C"); sheet.setValue(10, 1, "Total Budget"); sheet.getCell(10, 2).formula("=C8+C9"); sheet.getCell(10, 3).formula("=D8"); sheet.getCell(10, 4).formula("=C11-D11"); sheet.getRange(10, 1, 1, 4).font("bold 12pt Arial"); sheet.getRange(10, 2, 1, 3).backColor("#C6EFCE"); sheet.getRange(2, 2, 9, 3).formatter("$#,##0.00;[Red]-$#,##0.00"); } async function loadReplies() { if (activeThreadedComment) { var replies = activeThreadedComment.all(); var repliesList = _getElementById("repliesList"); repliesList.innerHTML = ""; if (replies && replies.length > 0) { for (var index = 0; index < replies.length; index++) { var reply = replies[index]; var option = document.createElement("option"); option.value = index; var message = ""; if (reply.message && reply.message.length > 0) { var messageParts = []; for (var i = 0; i < reply.message.length; i++) { var part = reply.message[i]; if (part.type === GC.Spread.Sheets.ThreadedComments.ContentType.text) { messageParts.push(part.value); } else if (part.type === GC.Spread.Sheets.ThreadedComments.ContentType.mention) { var user = await GC.Spread.Common.UserManager.get(part.userId); messageParts.push("@" + (user ? user.name : part.userId)); } else if (part.type === GC.Spread.Sheets.ThreadedComments.ContentType.link) { messageParts.push(part.text || part.href); } } message = messageParts.join(""); } option.text = "Reply " + (index + 1) + ": " + message.substring(0, 30) + (message.length > 30 ? "..." : ""); repliesList.appendChild(option); } } else { var option = document.createElement("option"); option.text = "No replies"; repliesList.appendChild(option); } } } function clearReplies() { var repliesList = _getElementById("repliesList"); repliesList.innerHTML = ""; var option = document.createElement("option"); option.text = "No replies loaded"; repliesList.appendChild(option); } function bindButtonEvents(spread) { // Select reply _getElementById("repliesList").addEventListener('change', function () { if (activeThreadedComment && this.value !== "") { activeReplyIndex = parseInt(this.value); updateLabels(spread); } }); // Add new reply _getElementById("btnAddReply").addEventListener('click', function () { if (activeThreadedComment) { var message = _getElementById("txtNewReply").value; if (message) { activeThreadedComment.add({ message: [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: message } ], authorId: GC.Spread.Common.UserManager.current(), createdAt: new Date() }); _getElementById("txtNewReply").value = ""; loadReplies(); updateLabels(spread); } } }); // Delete reply _getElementById("btnDeleteReply").addEventListener('click', function () { if (activeThreadedComment && activeReplyIndex !== null) { var replies = activeThreadedComment.all(); var replyToDelete = replies[activeReplyIndex]; if (replyToDelete) { activeThreadedComment.remove(activeReplyIndex); activeReplyIndex = null; loadReplies(); updateLabels(spread); } } }); // Toggle resolved status _getElementById("btnToggleResolved").addEventListener('click', function () { if (activeThreadedComment) { var currentStatus = activeThreadedComment.resolved(); activeThreadedComment.resolved(!currentStatus); updateLabels(spread); } }); // Delete entire thread _getElementById("btnDeleteThread").addEventListener('click', function () { if (activeThreadedComment) { var sheet = spread.getActiveSheet(); var row = sheet.getActiveRowIndex(); var col = sheet.getActiveColumnIndex(); sheet.threadedComments.remove(row, col); activeThreadedComment = null; activeReplyIndex = null; updateLabels(spread); clearReplies(); } }); // Add new thread _getElementById("btnAddThread").addEventListener('click', function () { var sheet = spread.getActiveSheet(); var row = sheet.getActiveRowIndex(); var col = sheet.getActiveColumnIndex(); var message = _getElementById("txtNewThread").value; if (message) { var existingComment = sheet.threadedComments.get(row, col); if (existingComment) { sheet.threadedComments.remove(row, col); } var tc = sheet.threadedComments.add(row, col); tc.add({ message: [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: message } ], authorId: GC.Spread.Common.UserManager.current(), createdAt: new Date() }); _getElementById("txtNewThread").value = ""; activeThreadedComment = tc; updateLabels(spread); } }); // Update reply message _getElementById("btnUpdateReply").addEventListener('click', function () { if (activeThreadedComment && activeReplyIndex !== null) { var newMessage = _getElementById("txtUpdateMessage").value; if (newMessage) { var replies = activeThreadedComment.all(); var replyToUpdate = replies[activeReplyIndex]; if (replyToUpdate) { replyToUpdate.message = [ { type: GC.Spread.Sheets.ThreadedComments.ContentType.text, value: newMessage } ]; replyToUpdate.modifiedAt = new Date(); activeThreadedComment.set(activeReplyIndex, replyToUpdate); _getElementById("txtUpdateMessage").value = ""; loadReplies(); updateLabels(spread); } } } }); // Change current user _getElementById("comboCurrentUser").addEventListener('change', function () { var userId = this.value; GC.Spread.Common.UserManager.current(userId); }); } async function updateLabels(spread) { // Clear all fields first _getElementById("lblThreadLocation").innerHTML = "-"; _getElementById("lblThreadResolved").innerHTML = "-"; _getElementById("lblThreadRepliesCount").innerHTML = "-"; _getElementById("lblReplyAuthor").innerHTML = "-"; _getElementById("lblReplyCreatedAt").innerHTML = "-"; _getElementById("lblReplyMessage").innerHTML = "-"; if (activeThreadedComment) { _getElementById("lblThreadLocation").innerHTML = "Row: " + activeThreadedComment.row() + ", Col: " + activeThreadedComment.col(); _getElementById("lblThreadResolved").innerHTML = activeThreadedComment.resolved() ? "Yes" : "No"; var replies = activeThreadedComment.all(); _getElementById("lblThreadRepliesCount").innerHTML = replies.length.toString(); if (activeReplyIndex !== null) { var activeReply = replies[activeReplyIndex]; if (activeReply) { // Get author name from UserManager var authorUser = await GC.Spread.Common.UserManager.get(activeReply.authorId); _getElementById("lblReplyAuthor").innerHTML = authorUser ? authorUser.name : (activeReply.authorId || "-"); _getElementById("lblReplyCreatedAt").innerHTML = activeReply.createdAt ? activeReply.createdAt.toLocaleString() : "-"; if (activeReply.message && activeReply.message.length > 0) { var messageParts = []; for (var i = 0; i < activeReply.message.length; i++) { var part = activeReply.message[i]; if (part.type === GC.Spread.Sheets.ThreadedComments.ContentType.text) { messageParts.push(part.value); } else if (part.type === GC.Spread.Sheets.ThreadedComments.ContentType.mention) { var user = await GC.Spread.Common.UserManager.get(part.userId); messageParts.push("@" + (user ? user.name : part.userId)); } else if (part.type === GC.Spread.Sheets.ThreadedComments.ContentType.link) { messageParts.push('<a href="' + part.href + '" target="_blank">' + (part.text || part.href) + '</a>'); } } _getElementById("lblReplyMessage").innerHTML = messageParts.join(""); } } } } spread.refresh(); } function _getElementById(id) { return document.getElementById(id); }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta name="spreadjs culture" content="zh-cn" /> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-resources-zh/dist/gc.spread.sheets.resources.zh.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div class="tc-sample-tutorial"> <div id="ss" class="tc-sample-spreadsheets"></div> <div class="tc-options-container"> <div class="tc-option-row"> <h4 class="tc-title">选择带有线程批注的单元格: <span id="commentTip" class="tc-comment-tip">无线程批注</span> </h4> </div> <!-- 当前用户选择 --> <div class="tc-section"> <h5 class="tc-section-title">当前用户</h5> <div class="tc-option-row"> <label class="tc-label">切换用户:</label> <select id="comboCurrentUser" class="tc-select" style="width: 100%;"> <option value="{715CFD19-2BB9-4B94-DE0C-08D0F9A019DB}">Alice Johnson</option> <option value="{8A3E2F47-5C1D-4E8B-A9F2-3B7C6D8E9F01}">Bob Smith</option> <option value="{C4D5E6F7-8A9B-0C1D-2E3F-4A5B6C7D8E9F}">Carol Manager</option> <option value="{D1E2F3A4-B5C6-7D8E-9F0A-1B2C3D4E5F67}">David Accountant</option> </select> </div> </div> <!-- 线程信息 --> <div class="tc-section"> <h5 class="tc-section-title">线程信息</h5> <div class="tc-info-row"> <label class="tc-label">位置:</label> <span id="lblThreadLocation" class="tc-info-value">-</span> </div> <div class="tc-info-row"> <label class="tc-label">已解决:</label> <span id="lblThreadResolved" class="tc-info-value">-</span> </div> <div class="tc-info-row"> <label class="tc-label">回复数量:</label> <span id="lblThreadRepliesCount" class="tc-info-value">-</span> </div> </div> <!-- 线程操作 --> <div class="tc-section"> <h5 class="tc-section-title">线程操作</h5> <div class="tc-option-row"> <input type="text" id="txtNewThread" class="tc-input" placeholder="输入线程消息..." style="width: 100%; margin-bottom: 6px;" /> <button id="btnAddThread" class="tc-btn tc-btn-primary">添加新线程</button> </div> <div class="tc-option-row"> <button id="btnToggleResolved" class="tc-btn tc-btn-secondary">切换解决状态</button> <button id="btnDeleteThread" class="tc-btn tc-btn-danger">删除线程</button> </div> </div> <!-- 回复管理 --> <div class="tc-section"> <h5 class="tc-section-title">回复管理</h5> <div class="tc-option-row"> <label class="tc-label">选择回复:</label> <select id="repliesList" class="tc-select" size="4" style="width: 100%; margin-top: 4px;"> <option>未加载回复</option> </select> </div> </div> <!-- 回复信息 --> <div class="tc-section"> <h5 class="tc-section-title">已选回复信息</h5> <div class="tc-info-row"> <label class="tc-label">作者:</label> <span id="lblReplyAuthor" class="tc-info-value">-</span> </div> <div class="tc-info-row"> <label class="tc-label">创建时间:</label> <span id="lblReplyCreatedAt" class="tc-info-value">-</span> </div> <div class="tc-info-row"> <label class="tc-label">消息:</label> <span id="lblReplyMessage" class="tc-info-value">-</span> </div> </div> <!-- 回复操作 --> <div class="tc-section"> <h5 class="tc-section-title">回复操作</h5> <div class="tc-option-row"> <input type="text" id="txtNewReply" class="tc-input" placeholder="输入回复消息..." style="width: 100%; margin-bottom: 6px;" /> <button id="btnAddReply" class="tc-btn tc-btn-primary">添加回复</button> </div> <div class="tc-option-row"> <input type="text" id="txtUpdateMessage" class="tc-input" placeholder="输入新消息..." style="width: 100%; margin-bottom: 6px;" /> <button id="btnUpdateReply" class="tc-btn tc-btn-secondary">更新已选回复</button> </div> <div class="tc-option-row"> <button id="btnDeleteReply" class="tc-btn tc-btn-danger">删除已选回复</button> </div> </div> </div> </div> </body> </html>
/* Container styles with specific prefixes */ .tc-sample-tutorial { position: relative; height: 100%; overflow: hidden; } .tc-sample-spreadsheets { width: calc(100% - 320px); height: 100%; overflow: hidden; float: left; } .tc-options-container { float: right; width: 320px; overflow: auto; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; } /* Title styles */ .tc-title { margin: 0 0 12px 0; font-size: 15px; color: #333; } .tc-comment-tip { color: #007acc; font-weight: bold; } /* Section styles */ .tc-section { margin-bottom: 20px; padding: 12px; background: white; border: 1px solid #ddd; border-radius: 4px; } .tc-section-title { margin: 0 0 12px 0; padding-bottom: 8px; border-bottom: 2px solid #007acc; color: #333; font-size: 14px; font-weight: bold; } .tc-option-row { margin-bottom: 10px; } .tc-info-row { display: flex; align-items: center; margin-bottom: 8px; padding: 6px; background: #f9f9f9; border-radius: 3px; } .tc-info-row .tc-label { min-width: 100px; font-weight: bold; color: #555; display: inline-flex; align-items: center; margin: 0; } .tc-info-value { flex: 1; word-wrap: break-word; color: #333; display: inline-flex; align-items: center; min-height: 24px; } /* Form element styles */ .tc-label { display: inline-block; min-width: 100px; margin: 6px 0; font-weight: 500; color: #333; } .tc-input { padding: 6px 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 3px; font-size: 13px; } .tc-select { padding: 6px 8px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 3px; font-size: 13px; } /* Button styles */ .tc-btn { padding: 8px 12px; margin: 4px 4px 4px 0; border: none; border-radius: 3px; cursor: pointer; font-size: 13px; font-weight: 500; transition: background-color 0.2s; } .tc-btn-primary { background-color: #007acc; color: white; } .tc-btn-primary:hover { background-color: #005a9e; } .tc-btn-secondary { background-color: #5c6bc0; color: white; } .tc-btn-secondary:hover { background-color: #3f51b5; } .tc-btn-danger { background-color: #e53935; color: white; } .tc-btn-danger:hover { background-color: #c62828; } .tc-btn-info { background-color: #26a69a; color: white; } .tc-btn-info:hover { background-color: #00897b; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; }