客户支持工单工作流自动化
高级
这是一个Content Creation, Multimodal AI领域的自动化工作流,包含 28 个节点。主要使用 If, Set, Code, Slack, Webhook 等节点。 使用GPT-4、PDF和Google Drive将支持工单转换为AI文档
前置要求
- •Slack Bot Token 或 Webhook URL
- •HTTP Webhook 端点(n8n 会自动生成)
- •Google Drive API 凭证
- •可能需要目标 API 的认证凭证
- •Google Sheets API 凭证
- •OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "support-ticket-documentation",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "客户支持工单工作流自动化",
"tags": [],
"nodes": [
{
"id": "61dc2aa7-ac6c-4397-bcbc-ad6014d1b117",
"name": "Webhook - 接收工单",
"type": "n8n-nodes-base.webhook",
"position": [
-2352,
240
],
"webhookId": "",
"parameters": {
"path": "support-ticket-resolved",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 1
},
{
"id": "3a08bb55-109b-4bce-ae0c-1a8bd6bd8233",
"name": "📝 便签 - 触发器设置",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2688,
48
],
"parameters": {
"color": 7,
"width": 468,
"height": 804,
"content": "## 🎯 步骤 1:触发器"
},
"typeVersion": 1
},
{
"id": "01277a43-c6fa-4a85-bb95-5e6fa1b096ff",
"name": "提取工单详情",
"type": "n8n-nodes-base.code",
"position": [
-2064,
240
],
"parameters": {
"jsCode": "// Extract and normalize ticket data from webhook payload\nconst ticketData = $input.item.json.body || $input.item.json;\n\n// Handle different payload structures (Zendesk, Freshdesk, custom)\nconst ticket = ticketData.ticket || ticketData;\n\n// Extract ticket ID (handle various formats)\nconst extractTicketId = (ticket) => {\n return ticket.id || ticket.ticket_id || ticket.number || 'UNKNOWN';\n};\n\n// Extract agent name with fallback\nconst extractAgentName = (ticket) => {\n if (ticket.assignee?.name) return ticket.assignee.name;\n if (ticket.agent?.name) return ticket.agent.name;\n if (ticket.assigned_to) return ticket.assigned_to;\n return 'Support Team';\n};\n\n// Extract customer info\nconst extractCustomerInfo = (ticket) => {\n return {\n name: ticket.requester?.name || ticket.customer?.name || 'Customer',\n email: ticket.requester?.email || ticket.customer?.email || 'N/A'\n };\n};\n\n// Extract resolution notes\nconst extractResolution = (ticket) => {\n if (ticket.resolution_notes) return ticket.resolution_notes;\n if (ticket.latest_comment?.body) return ticket.latest_comment.body;\n if (ticket.internal_notes) return ticket.internal_notes;\n if (Array.isArray(ticket.comments) && ticket.comments.length > 0) {\n return ticket.comments[ticket.comments.length - 1].body;\n }\n return 'Resolution details not available';\n};\n\nconst customer = extractCustomerInfo(ticket);\n\n// Return normalized data structure\nreturn {\n json: {\n ticketId: extractTicketId(ticket),\n subject: ticket.subject || 'No Subject Provided',\n description: ticket.description || ticket.body || '',\n resolution: extractResolution(ticket),\n agentName: extractAgentName(ticket),\n customerName: customer.name,\n customerEmail: customer.email,\n priority: (ticket.priority || 'normal').toLowerCase(),\n createdAt: ticket.created_at || new Date().toISOString(),\n resolvedAt: ticket.updated_at || ticket.resolved_at || new Date().toISOString(),\n tags: ticket.tags || [],\n category: ticket.category || ticket.type || 'General Support',\n rawTicket: ticket // Keep original for reference\n }\n};"
},
"typeVersion": 2
},
{
"id": "8e5339a1-47ac-466a-a5ab-ae753c10864a",
"name": "📝 便签 - 数据提取",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2192,
-528
],
"parameters": {
"color": 7,
"width": 404,
"height": 904,
"content": "## 📋 步骤 2:数据提取"
},
"typeVersion": 1
},
{
"id": "708ee78b-72c0-4a45-b334-8cdd845f9af8",
"name": "AI 摘要生成 (OpenAI)",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
-1728,
240
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4",
"cachedResultName": "GPT-4"
},
"options": {
"maxTokens": 1500,
"temperature": 0.3
},
"messages": {
"values": [
{
"content": "=You are a technical support documentation specialist. Your task is to analyze support tickets and create clear, professional case study summaries.\n\nCreate summaries that are:\n- Clear and professional\n- Structured with proper HTML formatting\n- Actionable and informative\n- Suitable for knowledge base articles\n- Include key takeaways and prevention tips"
},
{
"content": "=Please analyze this support ticket and provide a comprehensive, structured summary:\n\n**TICKET INFORMATION**\n- Ticket ID: {{ $json.ticketId }}\n- Subject: {{ $json.subject }}\n- Customer: {{ $json.customerName }} ({{ $json.customerEmail }})\n- Priority: {{ $json.priority }}\n- Category: {{ $json.category }}\n- Tags: {{ $json.tags.join(', ') }}\n\n**ORIGINAL ISSUE REPORTED:**\n{{ $json.description }}\n\n**RESOLUTION PROVIDED:**\n{{ $json.resolution }}\n\n**RESOLVED BY:** {{ $json.agentName }}\n\n---\n\nPlease structure your response using the following HTML format:\n\n<h2>🔍 Issue Reported</h2>\n<div class=\"section\">\n<p>[Provide a clear, concise description of the problem the customer experienced. Include symptoms, error messages, and impact on the customer.]</p>\n</div>\n\n<h2>🛠️ Troubleshooting Steps</h2>\n<div class=\"section\">\n<ul>\n<li>[Step 1: What was checked or attempted first]</li>\n<li>[Step 2: Next diagnostic action taken]</li>\n<li>[Step 3: Additional troubleshooting performed]</li>\n</ul>\n</div>\n\n<h2>✅ Final Resolution</h2>\n<div class=\"section\">\n<p>[Describe the exact solution that resolved the issue. Be specific about what was done and why it worked.]</p>\n</div>\n\n<h2>💡 Key Takeaways</h2>\n<div class=\"section\">\n<ul>\n<li>[Important lesson or insight from this case]</li>\n<li>[Prevention tip or best practice]</li>\n<li>[Related knowledge or documentation reference]</li>\n</ul>\n</div>\n\nIMPORTANT: \n- Use only the HTML tags and structure shown above\n- Be specific and technical but keep language clear\n- Focus on actionable information\n- If information is missing, make reasonable inferences based on context\n- Keep the summary concise but comprehensive (aim for 200-400 words total)"
}
]
}
},
"credentials": {
"openAiApi": {
"id": "1",
"name": "OpenAI Account"
}
},
"typeVersion": 1
},
{
"id": "aa238d8e-b227-4bf1-b3c7-218457f58e4c",
"name": "📝 便签 - AI 摘要生成",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1760,
-560
],
"parameters": {
"color": 7,
"width": 452,
"height": 916,
"content": "## 🤖 步骤 3:AI 摘要生成"
},
"typeVersion": 1
},
{
"id": "6ce3cdf9-7619-4f8a-973a-a0021a22e13d",
"name": "格式化 HTML 文档",
"type": "n8n-nodes-base.code",
"position": [
-1152,
240
],
"parameters": {
"jsCode": "// Combine ticket data with AI summary and create professional HTML document\nconst ticket = $('Extract Ticket Details').item.json;\nconst aiResponse = $input.item.json;\n\n// Extract AI summary (handle different response formats)\nlet aiSummary = '';\nif (aiResponse.message?.content) {\n aiSummary = aiResponse.message.content;\n} else if (aiResponse.choices?.[0]?.message?.content) {\n aiSummary = aiResponse.choices[0].message.content;\n} else if (typeof aiResponse === 'string') {\n aiSummary = aiResponse;\n} else {\n aiSummary = JSON.stringify(aiResponse);\n}\n\n// Format dates nicely\nconst formatDate = (dateString) => {\n const date = new Date(dateString);\n return date.toLocaleDateString('en-US', { \n year: 'numeric', \n month: 'long', \n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n });\n};\n\n// Calculate resolution time\nconst calculateResolutionTime = (created, resolved) => {\n const diff = new Date(resolved) - new Date(created);\n const hours = Math.floor(diff / (1000 * 60 * 60));\n const days = Math.floor(hours / 24);\n \n if (days > 0) return `${days} day${days > 1 ? 's' : ''}`;\n if (hours > 0) return `${hours} hour${hours > 1 ? 's' : ''}`;\n return 'Less than 1 hour';\n};\n\nconst resolutionTime = calculateResolutionTime(ticket.createdAt, ticket.resolvedAt);\nconst currentDate = new Date().toLocaleDateString('en-US', { \n year: 'numeric', \n month: 'long', \n day: 'numeric' \n});\n\n// Create comprehensive HTML document\nconst html = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Support Ticket ${ticket.ticketId} - Case Documentation</title>\n <style>\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n body {\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n line-height: 1.6;\n color: #333;\n background-color: #f5f7fa;\n padding: 0;\n }\n .page {\n background-color: white;\n max-width: 800px;\n margin: 0 auto;\n padding: 40px;\n min-height: 100vh;\n }\n .header {\n border-bottom: 4px solid #4CAF50;\n padding-bottom: 25px;\n margin-bottom: 35px;\n }\n .logo {\n color: #4CAF50;\n font-size: 28px;\n font-weight: bold;\n margin-bottom: 5px;\n display: flex;\n align-items: center;\n gap: 10px;\n }\n .company-tagline {\n color: #666;\n font-size: 14px;\n font-style: italic;\n margin-bottom: 20px;\n }\n h1 {\n color: #2c3e50;\n margin: 10px 0;\n font-size: 32px;\n font-weight: 700;\n }\n .badges {\n margin-top: 15px;\n }\n .badge {\n display: inline-block;\n padding: 6px 14px;\n border-radius: 20px;\n font-size: 11px;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-right: 8px;\n }\n .badge-resolved {\n background-color: #4CAF50;\n color: white;\n }\n .badge-priority-high {\n background-color: #f44336;\n color: white;\n }\n .badge-priority-urgent {\n background-color: #d32f2f;\n color: white;\n }\n .badge-priority-normal {\n background-color: #ff9800;\n color: white;\n }\n .badge-priority-low {\n background-color: #2196F3;\n color: white;\n }\n .meta-info {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 20px;\n background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\n padding: 25px;\n border-radius: 8px;\n margin-bottom: 35px;\n border: 1px solid #dee2e6;\n }\n .meta-item {\n font-size: 14px;\n }\n .meta-label {\n font-weight: 700;\n color: #495057;\n display: block;\n margin-bottom: 5px;\n text-transform: uppercase;\n font-size: 11px;\n letter-spacing: 0.5px;\n }\n .meta-value {\n color: #212529;\n font-size: 15px;\n font-weight: 500;\n }\n h2 {\n color: #4CAF50;\n border-left: 5px solid #4CAF50;\n padding-left: 15px;\n margin-top: 35px;\n margin-bottom: 20px;\n font-size: 22px;\n display: flex;\n align-items: center;\n gap: 10px;\n }\n .section {\n margin-bottom: 30px;\n padding: 20px;\n background-color: #fafbfc;\n border-radius: 6px;\n border-left: 3px solid #e9ecef;\n }\n .section p {\n margin-bottom: 12px;\n line-height: 1.8;\n }\n .section ul {\n margin: 15px 0;\n padding-left: 25px;\n }\n .section li {\n margin-bottom: 10px;\n line-height: 1.8;\n padding-left: 5px;\n }\n .tags {\n margin-top: 20px;\n padding-top: 20px;\n border-top: 1px solid #e9ecef;\n }\n .tag {\n display: inline-block;\n background-color: #e9ecef;\n color: #495057;\n padding: 5px 12px;\n border-radius: 12px;\n font-size: 12px;\n margin-right: 8px;\n margin-bottom: 8px;\n }\n .footer {\n margin-top: 50px;\n padding-top: 25px;\n border-top: 2px solid #e9ecef;\n text-align: center;\n font-size: 12px;\n color: #6c757d;\n }\n .footer-row {\n margin-bottom: 8px;\n }\n .stats-box {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n padding: 20px;\n border-radius: 8px;\n margin-bottom: 30px;\n text-align: center;\n }\n .stats-box .stat-label {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 1px;\n opacity: 0.9;\n margin-bottom: 5px;\n }\n .stats-box .stat-value {\n font-size: 24px;\n font-weight: bold;\n }\n </style>\n</head>\n<body>\n <div class=\"page\">\n <div class=\"header\">\n <div class=\"logo\">\n 🎯 Your Company Support\n </div>\n <div class=\"company-tagline\">Excellence in Customer Service</div>\n <h1>Support Case Documentation</h1>\n <div class=\"badges\">\n <span class=\"badge badge-resolved\">✓ RESOLVED</span>\n <span class=\"badge badge-priority-${ticket.priority}\">${ticket.priority.toUpperCase()} PRIORITY</span>\n </div>\n </div>\n\n <div class=\"stats-box\">\n <div class=\"stat-label\">Resolution Time</div>\n <div class=\"stat-value\">⚡ ${resolutionTime}</div>\n </div>\n\n <div class=\"meta-info\">\n <div class=\"meta-item\">\n <span class=\"meta-label\">Ticket ID</span>\n <div class=\"meta-value\">#${ticket.ticketId}</div>\n </div>\n <div class=\"meta-item\">\n <span class=\"meta-label\">Category</span>\n <div class=\"meta-value\">${ticket.category}</div>\n </div>\n <div class=\"meta-item\">\n <span class=\"meta-label\">Customer</span>\n <div class=\"meta-value\">${ticket.customerName}</div>\n </div>\n <div class=\"meta-item\">\n <span class=\"meta-label\">Customer Email</span>\n <div class=\"meta-value\">${ticket.customerEmail}</div>\n </div>\n <div class=\"meta-item\">\n <span class=\"meta-label\">Resolved By</span>\n <div class=\"meta-value\">${ticket.agentName}</div>\n </div>\n <div class=\"meta-item\">\n <span class=\"meta-label\">Resolution Date</span>\n <div class=\"meta-value\">${formatDate(ticket.resolvedAt)}</div>\n </div>\n </div>\n\n <h2>📋 Subject</h2>\n <div class=\"section\">\n <p><strong>${ticket.subject}</strong></p>\n </div>\n\n ${aiSummary}\n\n ${ticket.tags && ticket.tags.length > 0 ? `\n <div class=\"tags\">\n <strong>Tags:</strong><br>\n ${ticket.tags.map(tag => `<span class=\"tag\">#${tag}</span>`).join('')}\n </div>\n ` : ''}\n\n <div class=\"footer\">\n <div class=\"footer-row\">\n <strong>Document Generated:</strong> ${currentDate}\n </div>\n <div class=\"footer-row\">\n Case #${ticket.ticketId} | Ticket opened: ${formatDate(ticket.createdAt)}\n </div>\n <div class=\"footer-row\" style=\"margin-top: 15px;\">\n © ${new Date().getFullYear()} Your Company - Support Documentation System\n </div>\n <div class=\"footer-row\" style=\"margin-top: 10px; font-style: italic;\">\n This document was automatically generated by our AI-powered support documentation workflow\n </div>\n </div>\n </div>\n</body>\n</html>\n`;\n\n// Generate filename with timestamp\nconst timestamp = new Date().toISOString().split('T')[0];\nconst sanitizedSubject = ticket.subject\n .replace(/[^a-z0-9]/gi, '_')\n .substring(0, 50);\nconst fileName = `Ticket_${ticket.ticketId}_${sanitizedSubject}_${timestamp}.pdf`;\n\nreturn {\n json: {\n ...ticket,\n aiSummary: aiSummary,\n htmlContent: html,\n fileName: fileName,\n resolutionTime: resolutionTime,\n documentGeneratedAt: new Date().toISOString()\n }\n};"
},
"typeVersion": 2
},
{
"id": "7d4c30c8-8872-44fd-88d4-5f9b160a7799",
"name": "📝 便签 - HTML 格式化",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1296,
-752
],
"parameters": {
"color": 7,
"width": 436,
"height": 1116,
"content": "## 🎨 步骤 4:HTML 格式化"
},
"typeVersion": 1
},
{
"id": "75a14225-69a2-4db7-8dd3-d3e03b172f4a",
"name": "📝 便签 - PDF 转换",
"type": "n8n-nodes-base.stickyNote",
"position": [
-832,
-272
],
"parameters": {
"color": 7,
"width": 420,
"height": 668,
"content": "## 📄 步骤 5:PDF 转换"
},
"typeVersion": 1
},
{
"id": "34506c7f-ea7b-4d6f-9213-940cd56d6d37",
"name": "检查 PDF 成功",
"type": "n8n-nodes-base.if",
"position": [
-240,
240
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.success }}",
"operation": "isNotEmpty"
}
]
}
},
"typeVersion": 1
},
{
"id": "867a398d-8eca-4327-9555-6b153ba01c02",
"name": "📝 便签 - 错误检查",
"type": "n8n-nodes-base.stickyNote",
"position": [
-368,
-608
],
"parameters": {
"color": 7,
"width": 372,
"height": 980,
"content": "## ⚠️ 步骤 6:错误检查 #1"
},
"typeVersion": 1
},
{
"id": "726984c8-2e34-4881-9c99-4b07de711263",
"name": "上传到 Google Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
560,
112
],
"parameters": {
"name": "={{ $('Format HTML Document').item.json.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": "YOUR_FOLDER_ID_HERE"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"id": "3",
"name": "Google Drive account"
}
},
"typeVersion": 3
},
{
"id": "7eb6e69c-c2e4-4f9a-8b4b-e8e3a5cd8258",
"name": "📝 便签 - Drive 上传",
"type": "n8n-nodes-base.stickyNote",
"position": [
400,
-944
],
"parameters": {
"color": 7,
"width": 420,
"height": 1208,
"content": "## ☁️ 步骤 7:Google Drive 上传"
},
"typeVersion": 1
},
{
"id": "56bcd853-4095-4b0c-9bb0-d24f22dd8ed9",
"name": "捕获 Drive URL",
"type": "n8n-nodes-base.set",
"position": [
880,
112
],
"parameters": {
"fields": {
"values": [
{
"name": "driveFileId",
"stringValue": "={{ $json.id }}"
},
{
"name": "driveFileUrl",
"stringValue": "={{ $json.webViewLink }}"
},
{
"name": "driveFileName",
"stringValue": "={{ $json.name }}"
}
]
},
"options": {}
},
"typeVersion": 3
},
{
"id": "ecfdb162-21d7-4126-95fb-939aa0392065",
"name": "检查上传成功",
"type": "n8n-nodes-base.if",
"position": [
1264,
112
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.driveFileUrl }}",
"operation": "isNotEmpty"
}
]
}
},
"typeVersion": 1
},
{
"id": "f6be4bde-7607-46a2-b720-e97dfeea3e77",
"name": "📝 便签 - 上传检查",
"type": "n8n-nodes-base.stickyNote",
"position": [
1024,
-864
],
"parameters": {
"color": 7,
"width": 388,
"height": 1120,
"content": "## ⚠️ 步骤 8:错误检查 #2"
},
"typeVersion": 1
},
{
"id": "d66117e3-612e-4d2e-8630-154076c8d07a",
"name": "更新 Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
1600,
-96
],
"parameters": {
"columns": {
"value": {
"Status": "Documented",
"Subject": "={{ $('Extract Ticket Details').item.json.subject }}",
"Category": "={{ $('Extract Ticket Details').item.json.category }}",
"PDF Link": "={{ $json.driveFileUrl }}",
"Priority": "={{ $('Extract Ticket Details').item.json.priority }}",
"Ticket ID": "={{ $('Extract Ticket Details').item.json.ticketId }}",
"Agent Name": "={{ $('Extract Ticket Details').item.json.agentName }}",
"Customer Name": "={{ $('Extract Ticket Details').item.json.customerName }}",
"Resolved Date": "={{ $('Extract Ticket Details').item.json.resolvedAt }}",
"Customer Email": "={{ $('Extract Ticket Details').item.json.customerEmail }}",
"Resolution Time": "={{ $('Format HTML Document').item.json.resolutionTime }}",
"Document Generated": "={{ $now }}"
},
"schema": [
{
"id": "Ticket ID",
"type": "string",
"display": true,
"required": false,
"displayName": "Ticket ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Subject",
"type": "string",
"display": true,
"required": false,
"displayName": "Subject",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Customer Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Customer Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Customer Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Customer Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Agent Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Agent Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Priority",
"type": "string",
"display": true,
"required": false,
"displayName": "Priority",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Category",
"type": "string",
"display": true,
"required": false,
"displayName": "Category",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Resolved Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Resolved Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Resolution Time",
"type": "string",
"display": true,
"required": false,
"displayName": "Resolution Time",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "PDF Link",
"type": "string",
"display": true,
"required": false,
"displayName": "PDF Link",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Document Generated",
"type": "string",
"display": true,
"required": false,
"displayName": "Document Generated",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_SHEET_ID_HERE"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "4",
"name": "Google Sheets account"
}
},
"typeVersion": 4
},
{
"id": "896eb68c-5576-4584-ace7-ad48a2826d28",
"name": "📝 便签 - 数据库",
"type": "n8n-nodes-base.stickyNote",
"position": [
1456,
-1440
],
"parameters": {
"color": 7,
"width": 420,
"height": 1528,
"content": "## 步骤 9:数据库更新"
},
"typeVersion": 1
},
{
"id": "3fbf74bf-4418-4109-94c2-196a3e760e69",
"name": "发送 Slack 通知",
"type": "n8n-nodes-base.slack",
"position": [
2016,
-96
],
"webhookId": "",
"parameters": {
"text": "=✅ *Support Ticket Documented Successfully*\n\n*Ticket Details:*\n• *ID:* #{{ $('Extract Ticket Details').item.json.ticketId }}\n• *Subject:* {{ $('Extract Ticket Details').item.json.subject }}\n• *Customer:* {{ $('Extract Ticket Details').item.json.customerName }}\n• *Priority:* {{ $('Extract Ticket Details').item.json.priority.toUpperCase() }}\n\n*Resolution Info:*\n• *Resolved by:* {{ $('Extract Ticket Details').item.json.agentName }}\n• *Resolution Time:* {{ $('Format HTML Document').item.json.resolutionTime }}\n\n📄 *Documentation:* <{{ $('Capture Drive URL').item.json.driveFileUrl }}|View PDF>\n\n_Automatically generated at {{ $now.format('MM/DD/YYYY h:mm A') }}_",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "YOUR_CHANNEL_ID_HERE"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"id": "5",
"name": "Slack account"
}
},
"typeVersion": 2
},
{
"id": "f92ee144-07fe-474a-b3d8-6047b8fe1db3",
"name": "📝 便签 - Slack",
"type": "n8n-nodes-base.stickyNote",
"position": [
1920,
-1184
],
"parameters": {
"color": 7,
"width": 420,
"height": 1240,
"content": "## 💬 步骤 10:Slack 通知"
},
"typeVersion": 1
},
{
"id": "1259aa69-0636-4229-a0f9-072f024e068e",
"name": "Error - PDF Failed",
"type": "n8n-nodes-base.slack",
"position": [
208,
464
],
"webhookId": "",
"parameters": {
"text": "=🚨 *Support Documentation Workflow Failed*\n\n*Error:* PDF generation failed for ticket\n*Ticket ID:* #{{ $('Extract Ticket Details').item.json.ticketId }}\n*Subject:* {{ $('Extract Ticket Details').item.json.subject }}\n*Time:* {{ $now.format('MM/DD/YYYY h:mm A') }}\n\n*Action Required:*\nPlease check the n8n workflow execution logs and manually process this ticket.\n\n_Automated Error Alert_",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "YOUR_CHANNEL_ID_HERE"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"id": "5",
"name": "Slack account"
}
},
"typeVersion": 2
},
{
"id": "8ed1117f-2e16-4718-bc33-ea313098dc94",
"name": "Error - Upload Failed",
"type": "n8n-nodes-base.slack",
"position": [
1584,
240
],
"webhookId": "",
"parameters": {
"text": "=🚨 *Support Documentation Workflow Failed*\n\n*Error:* Google Drive upload failed\n*Ticket ID:* #{{ $('Extract Ticket Details').item.json.ticketId }}\n*Subject:* {{ $('Extract Ticket Details').item.json.subject }}\n*Time:* {{ $now.format('MM/DD/YYYY h:mm A') }}\n\n*Possible Causes:*\n• Drive storage quota exceeded\n• Invalid folder permissions\n• Authentication expired\n• Network timeout\n\n*Action Required:*\nCheck Google Drive credentials and storage, then retry this ticket.\n\n_Automated Error Alert_",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "YOUR_CHANNEL_ID_HERE"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"id": "5",
"name": "Slack account"
}
},
"typeVersion": 2
},
{
"id": "bed85817-521b-4b79-9205-549d1a4f348b",
"name": "📝 Sticky Note - Error Handling",
"type": "n8n-nodes-base.stickyNote",
"position": [
1504,
224
],
"parameters": {
"color": 7,
"width": 372,
"height": 1308,
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n## ERROR HANDLING\n\n**Purpose:** Catches and reports workflow failures\n\n**Error Scenarios Handled:**\n\n1. **PDF Generation Failed**\n - Invalid HTML syntax\n - Memory/timeout errors\n - Corrupted data\n - → Sends alert with ticket ID\n\n2. **Drive Upload Failed**\n - Storage quota exceeded\n - Permission issues\n - Network problems\n - Invalid credentials\n - → Sends alert with diagnosis\n\n**Error Notification Contains:**\n- Clear error description\n- Ticket ID for tracking\n- Timestamp of failure\n- Possible causes\n- Suggested actions\n\n**Recovery Process:**\n1. Admin receives Slack alert\n2. Reviews execution logs in n8n\n3. Identifies root cause\n4. Fixes issue (credentials, permissions, etc.)\n5. Manually retriggers for failed ticket\n\n**Advanced Error Handling:**\n- Set up retry logic (max 3 attempts)\n- Store failed tickets in separate database\n- Queue for batch reprocessing\n- Send daily error summary\n- Track error patterns\n\n**Monitoring Best Practices:**\n- Set up execution alerts\n- Monitor error rates\n- Track failure patterns\n- Review logs weekly\n- Document common fixes\n\n**Error Workflow (Optional):**\n- Create separate error workflow\n- Trigger on any node failure\n- Centralized error logging\n- More detailed diagnostics\n- Automatic retry capabilities"
},
"typeVersion": 1
},
{
"id": "48380fdf-d2e4-4a0a-9f1d-dd7213df7061",
"name": "📝 Sticky Note - Completion Guide",
"type": "n8n-nodes-base.stickyNote",
"position": [
2672,
-800
],
"parameters": {
"color": 7,
"width": 604,
"height": 1228,
"content": "## 🎉 WORKFLOW COMPLETE!\n\n**Congratulations!** Your automated support ticket documentation system is ready.\n\n**What You've Built:**\n✅ Automatic ticket capture from support tool\n✅ AI-powered intelligent summarization\n✅ Professional PDF documentation\n✅ Cloud storage with organized filing\n✅ Centralized tracking database\n✅ Team notifications\n✅ Comprehensive error handling\n\n**ROI Benefits:**\n- ⏱️ **Time Saved:** 15-30 min per ticket\n- 📈 **Scalability:** Handles 100s of tickets/day\n- 🎯 **Consistency:** Every ticket documented the same way\n- 🔍 **Searchability:** All cases indexed and findable\n- 📊 **Analytics:** Track patterns and metrics\n- 🧠 **Knowledge Base:** Build from real cases\n\n**Next Steps:**\n\n1. **Configure Credentials:**\n - OpenAI API key\n - Google Drive OAuth\n - Google Sheets OAuth\n - Slack app token\n\n2. **Customize:**\n - Replace \"Your Company\" with your brand\n - Update color scheme (#4CAF50 → your color)\n - Add logo URL in HTML\n - Modify PDF template\n - Adjust folder structure\n\n3. **Test Thoroughly:**\n - Use manual trigger with sample data\n - Verify each node output\n - Check PDF formatting\n - Confirm Drive upload\n - Test Slack notifications\n\n4. **Deploy:**\n - Activate workflow\n - Configure webhook in support tool\n - Monitor first few executions\n - Fine-tune as needed\n\n5. **Enhance (Optional):**\n - Add customer survey links\n - Create public knowledge base\n - Build analytics dashboard\n - Multi-language support\n - Confluence integration\n - Auto-categorization with ML"
},
"typeVersion": 1
},
{
"id": "df0d9c67-d252-45a0-91c5-ba6b73ec2b83",
"name": "HTML to PDF",
"type": "n8n-nodes-htmlcsstopdf.htmlcsstopdf",
"position": [
-704,
240
],
"parameters": {
"html_content": "={{ $json.htmlContent }}"
},
"credentials": {
"htmlcsstopdfApi": {
"id": "2",
"name": "HtmlcsstopdfApi account"
}
},
"typeVersion": 1
},
{
"id": "3e02523d-6776-466d-9233-2520e25c6647",
"name": "HTTP 请求",
"type": "n8n-nodes-base.httpRequest",
"position": [
160,
112
],
"parameters": {
"url": "={{ $json.pdf_url }}",
"options": {
"response": {
"response": {}
}
}
},
"typeVersion": 4.2
},
{
"id": "b8cd13d5-994a-4c59-9c14-55f96cd44af4",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2688,
896
],
"parameters": {
"color": 7,
"width": 480,
"height": 1280,
"content": "# Workflow Credentials Setup\n\n## Required Credentials\n\n### 1. OpenAI API\n- Get key from: https://platform.openai.com/api-keys\n- In n8n: Add credential → OpenAI API\n\n### 2. PDFMunk API\n- Get key from: https://pdfmunk.com (sign up free)\n- In n8n: Add credential → HtmlcsstopdfApi\n\n### 3. Google Drive OAuth2\n- Setup at: https://console.cloud.google.com\n- Enable Google Drive API\n- In n8n: Add credential → Google Drive OAuth2\n- **Needed:** Folder ID from Drive URL\n\n### 4. Google Sheets OAuth2\n- Same Google Cloud project as Drive\n- Enable Google Sheets API\n- In n8n: Add credential → Google Sheets OAuth2\n- **Needed:** Sheet ID from Sheets URL\n\n### 5. Slack OAuth2\n- Create app at: https://api.slack.com/apps\n- Scopes needed: `chat:write`, `chat:write.public`\n- In n8n: Add credential → Slack OAuth2 API\n- **Needed:** Channel ID\n\n## Configuration Checklist\n\n- [ ] OpenAI API key\n- [ ] PDFMunk API key\n- [ ] Google Drive OAuth2\n- [ ] Google Sheets OAuth2\n- [ ] Slack OAuth2\n- [ ] Drive Folder ID in upload node\n- [ ] Sheets ID in update node\n- [ ] Slack Channel ID in all 3 Slack nodes (1 success + 2 error nodes)\n\n## Quick IDs Reference\n\n**Folder ID:** `drive.google.com/drive/folders/[COPY_THIS]`\n\n**Sheet ID:** `docs.google.com/spreadsheets/d/[COPY_THIS]/edit`\n\n**Channel ID:** Right-click channel → View details → Copy ID"
},
"typeVersion": 1
},
{
"id": "1595445b-f5b9-47ce-a36d-9930bbd5083a",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
48,
-528
],
"parameters": {
"color": 7,
"width": 320,
"height": 784,
"content": "# PDF to Binary Conversion\n\n## Purpose\nDownloads PDF from PDFMunk URL and converts to binary data for Google Drive upload.\n\n## Configuration\n\n**Method:** GET\n\n**URL:** `{{ $json.pdf_url }}`\n\n**Authentication:** None\n\n**Options → Response:**\n- Response Format: `File`\n- Output Binary Data: `Yes`\n- Binary Property: `data`\n\n## Why Required\nPDFMunk returns a URL, but Google Drive needs binary file data. This node bridges the gap.\n "
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"connections": {
"HTML to PDF": {
"main": [
[
{
"node": "Check PDF Success",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request": {
"main": [
[
{
"node": "Upload to Google Drive",
"type": "main",
"index": 0
}
]
]
},
"Capture Drive URL": {
"main": [
[
{
"node": "Check Upload Success",
"type": "main",
"index": 0
}
]
]
},
"Check PDF Success": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
],
[
{
"node": "Error - PDF Failed",
"type": "main",
"index": 0
}
]
]
},
"Check Upload Success": {
"main": [
[
{
"node": "Update Google Sheets",
"type": "main",
"index": 0
}
],
[
{
"node": "Error - Upload Failed",
"type": "main",
"index": 0
}
]
]
},
"Format HTML Document": {
"main": [
[
{
"node": "HTML to PDF",
"type": "main",
"index": 0
}
]
]
},
"Update Google Sheets": {
"main": [
[
{
"node": "Send Slack Notification",
"type": "main",
"index": 0
}
]
]
},
"Extract Ticket Details": {
"main": [
[
{
"node": "AI Summarization (OpenAI)",
"type": "main",
"index": 0
}
]
]
},
"Upload to Google Drive": {
"main": [
[
{
"node": "Capture Drive URL",
"type": "main",
"index": 0
}
]
]
},
"Webhook - Receive Ticket": {
"main": [
[
{
"node": "Extract Ticket Details",
"type": "main",
"index": 0
}
]
]
},
"AI Summarization (OpenAI)": {
"main": [
[
{
"node": "Format HTML Document",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 内容创作, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
会议纪要和行动项跟踪器
基于AI的会议纪要:使用GPT-4、任务分配和多渠道分发
If
Set
Code
+10
38 节点Jitesh Dugar
内容创作
自动化推荐工作流
使用GPT-4处理推荐信,并通过Google表格自动生成社交媒体卡片
If
Set
Code
+9
34 节点Jitesh Dugar
社交媒体
防欺诈潜在客户捕获与培育系统
通过AI评分、表格跟踪和多渠道提醒捕获和培育防欺诈潜在客户
If
Set
Code
+11
28 节点Jitesh Dugar
内容创作
客户入职工作流
使用PDF、Trello、Slack、Gmail和Airtable简化客户入职流程
If
Code
Gmail
+10
22 节点Jitesh Dugar
内容创作
发票和收据生成器(HTML转PDF)
自动发票生成器 - 从Shopify到PDF,支持Google Drive存储和邮件发送
If
Code
Gmail
+6
19 节点Jitesh Dugar
内容创作
使用 OpenAI、QuickChart 和 Google Drive 将电子表格数据转换为智能图表
使用 OpenAI、QuickChart 和 Google Drive 将电子表格数据转换为智能图表
If
Set
Code
+18
82 节点LeeWei
内容创作
工作流信息
难度等级
高级
节点数量28
分类2
节点类型11
作者
Jitesh Dugar
@jiteshdugarAI Automation Specialist - OpenAI, CRM & Automation Expert with a solid understanding of various tools that include Zapier, Make, Zoho CRM, Hubspot, Google Sheets, Airtable, Pipedrive, Google Analytics, and more.
外部链接
在 n8n.io 查看 →
分享此工作流