关于 n8n-project-management
面向建筑项目管理者的 n8n 任务管理与报告系统,通过 Telegram 和 Google Sheets 分发任务、收集进度,并整理照片和位置报告。
主要功能
- 01通过 Telegram 定时发送任务提醒
- 02收集文字和照片状态报告
- 03记录工人的 GPS 坐标
- 04将任务数据保存到 Google Sheets
- 05为管理者提供仪表板视图
适用场景
- 01向施工班组分发每日任务
- 02收集现场工人的进度报告
- 03汇总里程碑照片和位置信息
- 04在共享仪表板查看任务状态
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ datadrivenconstruction/ ddc_skills_for_ai_agents_in_construction --skill n8n-project-management安装后在 Claude Code 中输入/n8n-project-management确认已加载。
附带文件claw.jsoninstructions.md
详细介绍
面向建筑施工的 n8n 项目管理系统
使用 n8n 自动化、Telegram 机器人和 Google Sheets,为建筑项目构建通用任务管理和报告系统。
商业案例
问题:施工经理每天要花 2-3 小时处理以下事务:
- 向工长和工人分配任务
- 通过电话/消息收集进度更新
- 汇总照片文档
- 跟踪任务完成状态
解决方案:自动化系统可实现:
- 在预定时间通过 Telegram 发送任务提醒
- 收集状态报告(文字 + 照片 + GPS)
- 自动将所有数据保存到 Google Sheets
- 为经理提供实时情况概览
投资回报:任务管理的行政时间减少 70%
源代码仓库
https://github.com/datadrivenconstruction/Project-management-n8n-with-task-management-and-photo-reports
系统架构
┌──────────────────────────────────────────────────────────────────────┐
│ PROJECT MANAGEMENT SYSTEM │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ MANAGER WORKER │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Google │ │ Telegram │ │
│ │ Sheets │ │ Bot │ │
│ │ │ │ │ │
│ │ • Tasks │ n8n │ • /start │ │
│ │ • Schedule │◄──Workflow──────►│ • Tasks │ │
│ │ • Reports │ │ • Photos │ │
│ │ • Photos │ │ • GPS │ │
│ └─────────────┘ └─────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Dashboard │ │ Google │ │
│ │ View │ │ Drive │ │
│ │ │ │ (Photos) │ │
│ └─────────────┘ └─────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
实施指南
步骤 1:创建 Telegram 机器人
# 1. Open @BotFather in Telegram
# 2. Send /newbot
# 3. Name: "YourProject Tasks Bot"
# 4. Username: "YourProjectTasks_bot"
# 5. Save the token: 123456789:ABCdefGHIjklMNOpqrsTUVwxyz
# Test bot connection
import requests
BOT_TOKEN = "YOUR_BOT_TOKEN"
response = requests.get(f"https://api.telegram.org/bot{BOT_TOKEN}/getMe")
print(response.json())
# Expected: {"ok": true, "result": {"id": ..., "first_name": "YourProject Tasks Bot"}}
步骤 2:设置 Google Sheets
创建包含以下工作表的电子表格:
工作表 1:Tasks
| 列 | 类型 | 说明 |
|---|---|---|
| Task_ID | Text | 唯一标识符(TASK-001) |
| Project | Text | 项目名称 |
| Object | Text | 建筑/区域 |
| Section | Text | 楼层/分区 |
| Task | Text | 任务描述 |
| Executor | Text | 指派的工人姓名 |
| Executor_ID | Number | Telegram 用户 ID |
| Date | Date | 截止日期(DD.MM.YYYY) |
| Send_Time | Time | 提醒时间 |
| Priority | Text | 🔴High / 🟡Medium / 🟢Low |
| Status | Text | Pending/Sent/Completed/Partial |
| Response | Text | 工人的回复 |
| Response_Time | DateTime | 回复时间 |
| Photo_Link | URL | Google Drive 链接 |
| GPS_Lat | Number | 纬度 |
| GPS_Lon | Number | 经度 |
工作表 2:Workers
| 列 | 类型 | 说明 |
|---|---|---|
| Name | Text | 工人全名 |
| Role | Text | 工长/工人/承包商 |
| Telegram_ID | Number | 通过 /start 获取的用户 ID |
| Phone | Text | 电话号码 |
| Registered | DateTime | 注册日期 |
工作表 3:Photo Reports
| 列 | 类型 | 说明 |
|---|---|---|
| Report_ID | Text | 唯一 ID |
| Report_Type | Text | 每日/安全/质量 |
| Executor | Text | 应提交报告的人 |
| Date | Date | 报告日期 |
| Time | Time | 截止时间 |
| Status | Text | Pending/Submitted |
| Photo_Link | URL | Drive 文件夹链接 |
| Comment | Text | 工人备注 |
步骤 3:导入 n8n 工作流
// Core workflow structure (simplified)
{
"nodes": [
{
"name": "Telegram Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"parameters": {
"updates": ["message", "callback_query"]
}
},
{
"name": "Route Messages",
"type": "n8n-nodes-base.switch",
"parameters": {
"rules": [
{"value": "/start"},
{"value": "/status"},
{"value": "/help"},
{"value": "text_reply"},
{"value": "photo"},
{"value": "location"}
]
}
},
{
"name": "Check Tasks Schedule",
"type": "n8n-nodes-base.cron",
"parameters": {
"cronExpression": "* * * * *"
}
},
{
"name": "Get Pending Tasks",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "readRows",
"sheetName": "Tasks",
"filters": {
"Status": "Pending",
"Send_Time": "now"
}
}
},
{
"name": "Send Task Reminder",
"type": "n8n-nodes-base.telegram",
"parameters": {
"operation": "sendMessage",
"chatId": "={{$json.Executor_ID}}",
"text": "📋 *Задача: {{$json.Task}}*\n📍 Объект: {{$json.Object}}\n⏰ Срок: {{$json.Date}}\n{{$json.Priority}}"
}
}
]
}
步骤 4:配置 Webhook
# Set Telegram webhook to n8n
curl -X POST "https://api.telegram.org/bot${BOT_TOKEN}/setWebhook" \
-d "url=https://your-n8n-instance.com/webhook/telegram-project-manager"
# Verify webhook is set
curl "https://api.telegram.org/bot${BOT_TOKEN}/getWebhookInfo"
工人命令
注册:/start
User: /start
Bot: 👋 Добро пожаловать в систему управления задачами!
Пожалуйста, укажите ваше имя:
User: Иван Петров
Bot: Выберите вашу роль:
[Прораб] [Рабочий] [Субподрядчик]
User: [Прораб]
Bot: ✅ Регистрация завершена!
Имя: Иван Петров
Роль: Прораб
ID: 123456789
Вы будете получать задачи автоматически.
Используйте /help для справки.
接收任务
Bot: 📋 *ЗАДАЧА #TASK-047*
━━━━━━━━━━━━━━━━━━━━━
📍 Объект: ЖК Солнечный, Корпус 2
🏗 Секция: 5 этаж, кв. 51-55
📝 Задача: Монтаж электропроводки
⏰ Срок: 24.01.2026
🔴 Приоритет: Высокий
━━━━━━━━━━━━━━━━━━━━━
Ответьте на это сообщение для отчета:
• Текст: статус + комментарий
• Фото: прикрепите фото работ
• GPS: отправьте геолокацию
任务回复
User: (reply to task message)
выполнено
Проводка смонтирована по всем квартирам, ждем приемку
Bot: ✅ Отчет принят!
━━━━━━━━━━━━━━━━━━━━━
📋 Задача: #TASK-047
📊 Статус: Выполнено
💬 Комментарий: Проводка смонтирована...
⏰ Время: 24.01.2026 14:35
━━━━━━━━━━━━━━━━━━━━━
照片报告
User: (sends photo as reply to task)
[Photo of completed electrical work]
Caption: Монтаж завершен, готово к проверке
Bot: 📷 Фото получено и сохранено!
━━━━━━━━━━━━━━━━━━━━━
📋 Задача: #TASK-047
🔗 Фото: [Ссылка на Google Drive]
💬 Комментарий: Монтаж завершен...
⏰ Время: 24.01.2026 14:38
━━━━━━━━━━━━━━━━━━━━━
GPS 位置
User: (sends location)
📍 [Location: 55.7558, 37.6173]
Bot: 📍 Геолокация получена!
━━━━━━━━━━━━━━━━━━━━━
📋 Задача: #TASK-047
🗺 Координаты: 55.7558, 37.6173
🔗 Карта: [Google Maps Link]
⏰ Время: 24.01.2026 14:40
━━━━━━━━━━━━━━━━━━━━━
经理仪表板
Google Sheets 视图
┌────────────────────────────────────────────────────────────────────────┐
│ TASK DASHBOARD 🔄 Auto-refresh │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ TODAY'S SUMMARY │
│ ┌───────────┬───────────┬───────────┬───────────┐ │
│ │ Total: 24 │ ✅ Done:15│ ⏳ Pending:7│ ⚠️ Late:2│ │
│ └───────────┴───────────┴───────────┴───────────┘ │
│ │
│ TASK LIST Filter: [Today ▼]│
│ ┌──────────┬────────────┬──────────┬────────┬────────┬──────────────┐│
│ │ Task ID │ Task │ Worker │ Status │ Photo │ Response ││
│ ├──────────┼────────────┼──────────┼────────┼────────┼──────────────┤│
│ │ TASK-047 │ Электрика │ Петров │ ✅ │ 📷 3 │ Выполнено ││
│ │ TASK-048 │ Сантехника │ Иванов │ ⏳ │ - │ - ││
│ │ TASK-049 │ Штукатурка │ Сидоров │ ⚠️ │ 📷 1 │ Частично ││
│ └──────────┴────────────┴──────────┴────────┴────────┴──────────────┘│
│ │
└────────────────────────────────────────────────────────────────────────┘
Python 集成
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import pandas as pd
from datetime import datetime, timedelta
class ProjectTaskManager:
"""Integration with n8n Project Management System"""
def __init__(self, credentials_path: str, spreadsheet_id: str):
scope = [
'https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive'
]
creds = ServiceAccountCredentials.from_json_keyfile_name(
credentials_path, scope
)
self.client = gspread.authorize(creds)
self.spreadsheet = self.client.open_by_key(spreadsheet_id)
def create_task(self, task: dict) -> str:
"""Create new task in system"""
tasks_sheet = self.spreadsheet.worksheet('Tasks')
# Generate task ID
all_tasks = tasks_sheet.get_all_records()
task_num = len(all_tasks) + 1
task_id = f"TASK-{task_num:04d}"
# Prepare row
row = [
task_id,
task.get('project', ''),
task.get('object', ''),
task.get('section', ''),
task.get('description', ''),
task.get('executor_name', ''),
task.get('executor_id', ''),
task.get('date', datetime.now().strftime('%d.%m.%Y')),
task.get('send_time', '09:00'),
task.get('priority', '🟡Medium'),
'Pending', # Status
'', # Response
'', # Response_Time
'', # Photo_Link
'', # GPS_Lat
'' # GPS_Lon
]
tasks_sheet.append_row(row)
return task_id
def create_bulk_tasks(self, tasks: list) -> list:
"""Create multiple tasks at once"""
task_ids = []
for task in tasks:
task_id = self.create_task(task)
task_ids.append(task_id)
return task_ids
def get_today_summary(self) -> dict:
"""Get summary of today's tasks"""
tasks_sheet = self.spreadsheet.worksheet('Tasks')
all_tasks = tasks_sheet.get_all_records()
today = datetime.now().strftime('%d.%m.%Y')
today_tasks = [t for t in all_tasks if t['Date'] == today]
return {
'total': len(today_tasks),
'completed': len([t for t in today_tasks if t['Status'] == 'Completed']),
'pending': len([t for t in today_tasks if t['Status'] == 'Pending']),
'partial': len([t for t in today_tasks if t['Status'] == 'Partial']),
'with_photos': len([t for t in today_tasks if t['Photo_Link']])
}
def get_worker_performance(self, worker_name: str, days: int = 30) -> dict:
"""Analyze worker performance over period"""
tasks_sheet = self.spreadsheet.worksheet('Tasks')
all_tasks = tasks_sheet.get_all_records()
cutoff_date = datetime.now() - timedelta(days=days)
worker_tasks = [
t for t in all_tasks
if t['Executor'] == worker_name
and datetime.strptime(t['Date'], '%d.%m.%Y') >= cutoff_date
]
if not worker_tasks:
return {'error': 'No tasks found'}
completed = len([t for t in worker_tasks if t['Status'] == 'Completed'])
total = len(worker_tasks)
return {
'worker': worker_name,
'period_days': days,
'total_tasks': total,
'completed': completed,
'completion_rate': round(completed / total * 100, 1),
'with_photos': len([t for t in worker_tasks if t['Photo_Link']]),
'with_gps': len([t for t in worker_tasks if t['GPS_Lat']])
}
# Usage Example
if __name__ == "__main__":
manager = ProjectTaskManager(
'credentials.json',
'your-spreadsheet-id'
)
# Create tasks for the week
weekly_tasks = [
{
'project': 'ЖК Солнечный',
'object': 'Корпус 2',
'section': '5 этаж',
'description': 'Монтаж электропроводки кв. 51-55',
'executor_name': 'Петров И.И.',
'executor_id': '123456789',
'date': '24.01.2026',
'send_time': '08:00',
'priority': '🔴High'
},
{
'project': 'ЖК Солнечный',
'object': 'Корпус 2',
'section': '5 этаж',
'description': 'Монтаж сантехники кв. 51-55',
'executor_name': 'Иванов А.П.',
'executor_id': '987654321',
'date': '25.01.2026',
'send_time': '08:00',
'priority': '🟡Medium'
}
]
task_ids = manager.create_bulk_tasks(weekly_tasks)
print(f"Created tasks: {task_ids}")
# Get summary
summary = manager.get_today_summary()
print(f"Today's summary: {summary}")
n8n 工作流模板
模板 1:早间任务分配
name: Morning Task Distribution
trigger:
type: cron
expression: "0 8 * * 1-6" # 8:00 AM, Mon-Sat
steps:
- get_today_tasks:
node: Google Sheets
operation: readRows
sheet: Tasks
filter: Date = TODAY(), Status = Pending
- group_by_worker:
node: Code
code: |
const grouped = {};
items.forEach(item => {
const worker = item.json.Executor_ID;
if (!grouped[worker]) grouped[worker] = [];
grouped[worker].push(item.json);
});
return Object.entries(grouped).map(([id, tasks]) => ({
worker_id: id,
tasks: tasks
}));
- send_task_list:
node: Telegram
operation: sendMessage
chatId: "={{$json.worker_id}}"
text: |
🌅 *Доброе утро! Ваши задачи на сегодня:*
{{#each tasks}}
━━━━━━━━━━━━━━━━━━━━━
{{priority}} *{{Task}}*
📍 {{Object}} / {{Section}}
⏰ Срок: {{Date}}
{{/each}}
Ответьте на каждую задачу по мере выполнения.
模板 2:照片报告收集
name: Scheduled Photo Reports
trigger:
type: cron
expression: "0 12,17 * * 1-6" # 12:00 and 17:00
steps:
- get_photo_reports:
node: Google Sheets
operation: readRows
sheet: Photo Reports
filter: Date = TODAY(), Status = Pending
- send_photo_request:
node: Telegram
operation: sendMessage
chatId: "={{$json.Executor_ID}}"
text: |
📷 *Требуется фото-отчет*
━━━━━━━━━━━━━━━━━━━━━
📋 Тип: {{$json.Report_Type}}
📍 Объект: {{$json.Object}}
⏰ Срок: {{$json.Time}}
Пожалуйста, отправьте фото с комментарием.
replyMarkup:
inline_keyboard:
- [{text: "📷 Отправить фото", callback_data: "photo_{{$json.Report_ID}}"}]
模板 3:每日工作总结
name: End of Day Report
trigger:
type: cron
expression: "0 18 * * 1-6" # 18:00
steps:
- get_day_stats:
node: Google Sheets
operation: readRows
sheet: Tasks
filter: Date = TODAY()
- calculate_stats:
node: Code
code: |
const stats = {
total: items.length,
completed: items.filter(i => i.json.Status === 'Completed').length,
partial: items.filter(i => i.json.Status === 'Partial').length,
pending: items.filter(i => i.json.Status === 'Pending').length,
photos: items.filter(i => i.json.Photo_Link).length
};
stats.completion_rate = Math.round(stats.completed / stats.total * 100);
return [{ json: stats }];
- send_to_manager:
node: Telegram
operation: sendMessage
chatId: "MANAGER_CHAT_ID"
text: |
📊 *Итоги дня: {{$now.format('DD.MM.YYYY')}}*
━━━━━━━━━━━━━━━━━━━━━
📋 Всего задач: {{$json.total}}
✅ Выполнено: {{$json.completed}}
⏳ Частично: {{$json.partial}}
❌ Не выполнено: {{$json.pending}}
📷 Фото-отчетов: {{$json.photos}}
📈 Выполнение: {{$json.completion_rate}}%
[Открыть таблицу]({{SPREADSHEET_URL}})
最佳实践
任务设计
- 将任务拆分为最小单元(1 个任务 = 1 个操作)
- 标明清晰的位置(Object + Section)
- 设定合理的截止时间
- 明智地使用优先级(并非所有任务都是 🔴High)
照片报告
- 在关键节点要求提交照片,而非持续提交
- 按项目/日期使用 Google Drive 文件夹
- 包含位置验证(GPS)
- 明确说明要求(照片中应包含什么)
工人参与
- 及时确认所有回复
- 每天提供反馈
- 表扬表现出色的人员
- 保持机器人消息简洁
资源
- 代码仓库:https://github.com/datadrivenconstruction/Project-management-n8n-with-task-management-and-photo-reports
- 演示机器人:@ProjectManagementTasks_Bot
- 演示表格:Google Sheets 演示
- n8n 文档:https://docs.n8n.io
“自动化不是为了取代人,而是让人腾出时间去做只有人才能做的事。”
评论
支持 Markdown