404 lines
14 KiB
Python
404 lines
14 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""
|
|||
|
|
===========================================
|
|||
|
|
📋 每日工作总结自动生成器
|
|||
|
|
功能:每天早上9点 → 生成今日工作总结 → 推送到指定渠道
|
|||
|
|
===========================================
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import json
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
import datetime
|
|||
|
|
import smtplib
|
|||
|
|
import requests
|
|||
|
|
from email.mime.text import MIMEText
|
|||
|
|
from email.mime.multipart import MIMEMultipart
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
# ===========================================
|
|||
|
|
# 📝 第一部分:配置区(请按需修改)
|
|||
|
|
# ===========================================
|
|||
|
|
|
|||
|
|
class Config:
|
|||
|
|
"""所有配置集中管理,方便修改"""
|
|||
|
|
|
|||
|
|
# --- 数据来源方式 ---
|
|||
|
|
# mode = "manual" → 手动输入今日事项
|
|||
|
|
# mode = "file" → 从文件读取今日事项
|
|||
|
|
DATA_MODE = "manual"
|
|||
|
|
|
|||
|
|
# 当 DATA_MODE = "file" 时,读取此文件
|
|||
|
|
DATA_FILE = "today_work_items.txt"
|
|||
|
|
|
|||
|
|
# --- 推送方式(可多选)---
|
|||
|
|
# 支持:wecom(企业微信)、dingtalk(钉钉)、email(邮件)
|
|||
|
|
PUSH_CHANNELS = ["wecom"] # 可改为 ["dingtalk"] 或 ["email"]
|
|||
|
|
|
|||
|
|
# ----- 企业微信机器人 -----
|
|||
|
|
WECOM_WEBHOOK = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY_HERE"
|
|||
|
|
|
|||
|
|
# ----- 钉钉机器人 -----
|
|||
|
|
DINGTALK_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN_HERE"
|
|||
|
|
|
|||
|
|
# ----- 邮件配置 -----
|
|||
|
|
SMTP_SERVER = "smtp.qq.com"
|
|||
|
|
SMTP_PORT = 465
|
|||
|
|
SMTP_USER = "your_email@qq.com"
|
|||
|
|
SMTP_PASSWORD = "your_auth_code" # 邮件授权码,非密码
|
|||
|
|
MAIL_TO = ["boss@company.com", "yourself@company.com"]
|
|||
|
|
|
|||
|
|
# --- 总结模板 ---
|
|||
|
|
SUMMARY_TEMPLATE = """
|
|||
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|||
|
|
📅 今日工作总结 · {date}
|
|||
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|||
|
|
|
|||
|
|
👤 姓名:{name}
|
|||
|
|
🏢 部门:{department}
|
|||
|
|
|
|||
|
|
📌 今日工作事项:
|
|||
|
|
{work_items}
|
|||
|
|
|
|||
|
|
📊 工作总结:
|
|||
|
|
{summary}
|
|||
|
|
|
|||
|
|
✅ 明日计划:
|
|||
|
|
{tomorrow_plan}
|
|||
|
|
|
|||
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|||
|
|
⏰ 生成时间:{generate_time}
|
|||
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ===========================================
|
|||
|
|
# 🔧 第二部分:核心功能
|
|||
|
|
# ===========================================
|
|||
|
|
|
|||
|
|
class WorkSummaryGenerator:
|
|||
|
|
"""工作总结生成器"""
|
|||
|
|
|
|||
|
|
def __init__(self, name="张三", department="技术部"):
|
|||
|
|
self.name = name
|
|||
|
|
self.department = department
|
|||
|
|
self.today = datetime.date.today()
|
|||
|
|
self.tomorrow = self.today + datetime.timedelta(days=1)
|
|||
|
|
|
|||
|
|
def get_work_items_from_input(self):
|
|||
|
|
"""方式一:手动输入今日工作事项"""
|
|||
|
|
print("\n📝 请输入你今天的工作事项(每行一条,输入空行结束):")
|
|||
|
|
print("(例:完成了XX功能开发 / 修复了XXbug / 参加了XX会议)\n")
|
|||
|
|
items = []
|
|||
|
|
while True:
|
|||
|
|
line = input(" ➜ ").strip()
|
|||
|
|
if not line:
|
|||
|
|
break
|
|||
|
|
items.append(line)
|
|||
|
|
return items
|
|||
|
|
|
|||
|
|
def get_work_items_from_file(self, filepath):
|
|||
|
|
"""方式二:从文件读取今日工作事项"""
|
|||
|
|
try:
|
|||
|
|
with open(filepath, "r", encoding="utf-8") as f:
|
|||
|
|
items = [line.strip() for line in f if line.strip()]
|
|||
|
|
return items
|
|||
|
|
except FileNotFoundError:
|
|||
|
|
print(f"⚠️ 文件 {filepath} 不存在,请先创建!")
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
def generate_summary(self, work_items):
|
|||
|
|
"""生成工作总结(基于规则+模板,你也可以接入AI API)"""
|
|||
|
|
if not work_items:
|
|||
|
|
return "今日暂无工作记录。"
|
|||
|
|
|
|||
|
|
# 统计信息
|
|||
|
|
total_items = len(work_items)
|
|||
|
|
|
|||
|
|
# 简单分类统计(关键词匹配)
|
|||
|
|
categories = {
|
|||
|
|
"开发": 0, "修复": 0, "会议": 0, "文档": 0,
|
|||
|
|
"测试": 0, "沟通": 0, "其他": 0
|
|||
|
|
}
|
|||
|
|
keywords_map = {
|
|||
|
|
"开发": ["开发", "编码", "编程", "实现", "搭建", "构建"],
|
|||
|
|
"修复": ["修复", "解决", "处理", "修改", "bug", "Bug"],
|
|||
|
|
"会议": ["会议", "评审", "讨论", "沟通会", "晨会", "周会"],
|
|||
|
|
"文档": ["文档", "文档", "方案", "设计", "PPT", "报告"],
|
|||
|
|
"测试": ["测试", "调试", "自测", "联调", "验证"],
|
|||
|
|
"沟通": ["沟通", "对齐", "同步", "协调", "对接"],
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for item in work_items:
|
|||
|
|
matched = False
|
|||
|
|
for cat, keywords in keywords_map.items():
|
|||
|
|
if any(kw in item for kw in keywords):
|
|||
|
|
categories[cat] += 1
|
|||
|
|
matched = True
|
|||
|
|
break
|
|||
|
|
if not matched:
|
|||
|
|
categories["其他"] += 1
|
|||
|
|
|
|||
|
|
# 生成总结文本
|
|||
|
|
summary_parts = [f"今日共完成 {total_items} 项工作,具体如下:\n"]
|
|||
|
|
|
|||
|
|
# 分类汇总
|
|||
|
|
active_cats = {k: v for k, v in categories.items() if v > 0}
|
|||
|
|
if active_cats:
|
|||
|
|
summary_parts.append("📊 工作类型分布:")
|
|||
|
|
for cat, count in active_cats.items():
|
|||
|
|
bar = "█" * count
|
|||
|
|
summary_parts.append(f" {cat}:{bar} {count}项")
|
|||
|
|
summary_parts.append("")
|
|||
|
|
|
|||
|
|
# 逐项列出
|
|||
|
|
summary_parts.append("📋 详细工作记录:")
|
|||
|
|
for i, item in enumerate(work_items, 1):
|
|||
|
|
summary_parts.append(f" {i}. {item}")
|
|||
|
|
|
|||
|
|
# 评价与建议
|
|||
|
|
summary_parts.append(f"\n💡 今日小结:今日工作效率{'较高' if total_items >= 5 else '正常'},"
|
|||
|
|
f"建议明日继续保持{'/优化时间管理' if total_items < 3 else ''}。")
|
|||
|
|
|
|||
|
|
return "\n".join(summary_parts)
|
|||
|
|
|
|||
|
|
def generate_tomorrow_plan(self):
|
|||
|
|
"""生成明日计划(可扩展为从配置文件读取)"""
|
|||
|
|
plan_items = [
|
|||
|
|
"继续推进当前开发任务",
|
|||
|
|
"同步项目进度",
|
|||
|
|
"代码审查",
|
|||
|
|
]
|
|||
|
|
return "\n".join(f" {i+1}. {item}" for i, item in enumerate(plan_items))
|
|||
|
|
|
|||
|
|
def build_summary_text(self, work_items, summary):
|
|||
|
|
"""组装完整的总结文本"""
|
|||
|
|
tomorrow_plan = self.generate_tomorrow_plan()
|
|||
|
|
formatted_items = "\n".join(f" • {item}" for item in work_items)
|
|||
|
|
|
|||
|
|
now_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|||
|
|
|
|||
|
|
return Config.SUMMARY_TEMPLATE.format(
|
|||
|
|
date=self.today.strftime("%Y年%m月%d日"),
|
|||
|
|
name=self.name,
|
|||
|
|
department=self.department,
|
|||
|
|
work_items=formatted_items if formatted_items else " (暂无记录)",
|
|||
|
|
summary=summary,
|
|||
|
|
tomorrow_plan=tomorrow_plan,
|
|||
|
|
generate_time=now_str
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def run(self):
|
|||
|
|
"""主运行流程"""
|
|||
|
|
print(f"\n{'='*50}")
|
|||
|
|
print(f"📅 今日工作总结生成器")
|
|||
|
|
print(f"📆 {self.today.strftime('%Y年%m月%d日')}")
|
|||
|
|
print(f"{'='*50}\n")
|
|||
|
|
|
|||
|
|
# 1️⃣ 获取工作事项
|
|||
|
|
if Config.DATA_MODE == "file":
|
|||
|
|
items = self.get_work_items_from_file(Config.DATA_FILE)
|
|||
|
|
else:
|
|||
|
|
items = self.get_work_items_from_input()
|
|||
|
|
|
|||
|
|
if not items:
|
|||
|
|
print("⚠️ 没有输入任何工作事项,将生成空总结。")
|
|||
|
|
|
|||
|
|
# 2️⃣ 生成总结
|
|||
|
|
summary = self.generate_summary(items)
|
|||
|
|
final_text = self.build_summary_text(items, summary)
|
|||
|
|
|
|||
|
|
# 3️⃣ 本地保存
|
|||
|
|
self.save_to_file(final_text)
|
|||
|
|
|
|||
|
|
# 4️⃣ 推送
|
|||
|
|
pusher = MessagePusher()
|
|||
|
|
pusher.push(final_text)
|
|||
|
|
|
|||
|
|
return final_text
|
|||
|
|
|
|||
|
|
def save_to_file(self, content):
|
|||
|
|
"""保存到本地文件"""
|
|||
|
|
filename = f"工作总结_{self.today.strftime('%Y%m%d')}.md"
|
|||
|
|
with open(filename, "w", encoding="utf-8") as f:
|
|||
|
|
f.write(content)
|
|||
|
|
print(f"\n✅ 已保存到本地文件:{os.path.abspath(filename)}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ===========================================
|
|||
|
|
# 📨 第三部分:消息推送
|
|||
|
|
# ===========================================
|
|||
|
|
|
|||
|
|
class MessagePusher:
|
|||
|
|
"""消息推送器"""
|
|||
|
|
|
|||
|
|
def push(self, content):
|
|||
|
|
"""根据配置推送消息到各个渠道"""
|
|||
|
|
for channel in Config.PUSH_CHANNELS:
|
|||
|
|
if channel == "wecom":
|
|||
|
|
self.push_wecom(content)
|
|||
|
|
elif channel == "dingtalk":
|
|||
|
|
self.push_dingtalk(content)
|
|||
|
|
elif channel == "email":
|
|||
|
|
self.push_email(content)
|
|||
|
|
else:
|
|||
|
|
print(f"⚠️ 未知推送渠道: {channel}")
|
|||
|
|
|
|||
|
|
def push_wecom(self, content):
|
|||
|
|
"""推送到企业微信机器人"""
|
|||
|
|
url = Config.WECOM_WEBHOOK
|
|||
|
|
if "YOUR_KEY_HERE" in url:
|
|||
|
|
print("⚠️ 跳过企业微信推送:未配置Webhook地址")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
data = {
|
|||
|
|
"msgtype": "markdown",
|
|||
|
|
"markdown": {"content": content}
|
|||
|
|
}
|
|||
|
|
try:
|
|||
|
|
resp = requests.post(url, json=data, timeout=10)
|
|||
|
|
result = resp.json()
|
|||
|
|
if result.get("errcode") == 0:
|
|||
|
|
print("✅ 企业微信推送成功!")
|
|||
|
|
else:
|
|||
|
|
print(f"⚠️ 企业微信推送失败: {result}")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"⚠️ 企业微信推送异常: {e}")
|
|||
|
|
|
|||
|
|
def push_dingtalk(self, content):
|
|||
|
|
"""推送到钉钉机器人"""
|
|||
|
|
url = Config.DINGTALK_WEBHOOK
|
|||
|
|
if "YOUR_TOKEN_HERE" in url:
|
|||
|
|
print("⚠️ 跳过钉钉推送:未配置Webhook地址")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
data = {
|
|||
|
|
"msgtype": "markdown",
|
|||
|
|
"markdown": {
|
|||
|
|
"title": "今日工作总结",
|
|||
|
|
"text": content
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
try:
|
|||
|
|
resp = requests.post(url, json=data, timeout=10)
|
|||
|
|
result = resp.json()
|
|||
|
|
if result.get("errcode") == 0:
|
|||
|
|
print("✅ 钉钉推送成功!")
|
|||
|
|
else:
|
|||
|
|
print(f"⚠️ 钉钉推送失败: {result}")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"⚠️ 钉钉推送异常: {e}")
|
|||
|
|
|
|||
|
|
def push_email(self, content):
|
|||
|
|
"""通过邮件推送"""
|
|||
|
|
if "your_email" in Config.SMTP_USER:
|
|||
|
|
print("⚠️ 跳过邮件推送:未配置邮箱信息")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
msg = MIMEMultipart()
|
|||
|
|
msg["From"] = Config.SMTP_USER
|
|||
|
|
msg["To"] = ", ".join(Config.MAIL_TO)
|
|||
|
|
msg["Subject"] = f"今日工作总结 - {datetime.date.today().strftime('%Y-%m-%d')}"
|
|||
|
|
|
|||
|
|
msg.attach(MIMEText(content, "plain", "utf-8"))
|
|||
|
|
|
|||
|
|
with smtplib.SMTP_SSL(Config.SMTP_SERVER, Config.SMTP_PORT) as server:
|
|||
|
|
server.login(Config.SMTP_USER, Config.SMTP_PASSWORD)
|
|||
|
|
server.sendmail(Config.SMTP_USER, Config.MAIL_TO, msg.as_string())
|
|||
|
|
|
|||
|
|
print("✅ 邮件推送成功!")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"⚠️ 邮件推送异常: {e}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ===========================================
|
|||
|
|
# 🚀 第四部分:程序入口
|
|||
|
|
# ===========================================
|
|||
|
|
|
|||
|
|
def setup_windows_task():
|
|||
|
|
"""生成Windows任务计划程序导入脚本"""
|
|||
|
|
script_path = os.path.abspath(sys.argv[0])
|
|||
|
|
python_path = sys.executable
|
|||
|
|
|
|||
|
|
cmd = f'''@echo off
|
|||
|
|
echo ========================================
|
|||
|
|
echo 设置每日9点自动运行工作总结脚本
|
|||
|
|
echo ========================================
|
|||
|
|
|
|||
|
|
REM 请以管理员身份运行此.bat文件
|
|||
|
|
|
|||
|
|
schtasks /create /tn "每日工作总结" /tr "{python_path} {script_path}" /sc daily /st 09:00 /f
|
|||
|
|
|
|||
|
|
if %errorlevel%==0 (
|
|||
|
|
echo ✅ 定时任务创建成功!每天早上9:00自动运行。
|
|||
|
|
) else (
|
|||
|
|
echo ❌ 创建失败,请尝试以管理员身份运行。
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
pause
|
|||
|
|
'''
|
|||
|
|
|
|||
|
|
bat_path = "setup_windows_task.bat"
|
|||
|
|
with open(bat_path, "w", encoding="utf-8") as f:
|
|||
|
|
f.write(cmd)
|
|||
|
|
print(f"\n📁 Windows定时任务脚本已生成:{os.path.abspath(bat_path)}")
|
|||
|
|
print(" → 右键点击该文件,选择「以管理员身份运行」即可设置定时任务!")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def setup_linux_cron():
|
|||
|
|
"""输出Linux crontab配置说明"""
|
|||
|
|
script_path = os.path.abspath(sys.argv[0])
|
|||
|
|
python_path = sys.executable
|
|||
|
|
|
|||
|
|
print("\n" + "="*50)
|
|||
|
|
print("🐧 Linux/macOS 定时任务设置(crontab)")
|
|||
|
|
print("="*50)
|
|||
|
|
print(f"在终端中执行以下命令添加定时任务:")
|
|||
|
|
print(f"\n crontab -e")
|
|||
|
|
print(f"\n然后添加一行:")
|
|||
|
|
print(f"\n 0 9 * * * {python_path} {script_path}")
|
|||
|
|
print(f"\n保存退出即可!📌")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
# 检查是否有命令行参数
|
|||
|
|
if len(sys.argv) > 1:
|
|||
|
|
arg = sys.argv[1].lower()
|
|||
|
|
if arg == "--setup-win":
|
|||
|
|
setup_windows_task()
|
|||
|
|
sys.exit(0)
|
|||
|
|
elif arg == "--setup-linux":
|
|||
|
|
setup_linux_cron()
|
|||
|
|
sys.exit(0)
|
|||
|
|
|
|||
|
|
print("""
|
|||
|
|
╔══════════════════════════════════════════╗
|
|||
|
|
║ 🍊 每日工作总结生成器 ║
|
|||
|
|
║ ║
|
|||
|
|
║ 用法: ║
|
|||
|
|
║ python daily_work_summary.py ║
|
|||
|
|
║ python daily_work_summary.py --setup-win ║
|
|||
|
|
║ python daily_work_summary.py --setup-linux ║
|
|||
|
|
╚══════════════════════════════════════════╝
|
|||
|
|
""")
|
|||
|
|
|
|||
|
|
# 运行主程序
|
|||
|
|
generator = WorkSummaryGenerator(name="张三", department="技术部")
|
|||
|
|
result = generator.run()
|
|||
|
|
|
|||
|
|
print("\n" + "="*50)
|
|||
|
|
print("🎉 工作总结生成完成!")
|
|||
|
|
print("="*50)
|
|||
|
|
|
|||
|
|
# 生成本地定时任务设置脚本
|
|||
|
|
if sys.platform == "win32":
|
|||
|
|
setup_windows_task()
|
|||
|
|
else:
|
|||
|
|
setup_linux_cron()
|
|||
|
|
|
|||
|
|
print("\n💡 小提示:修改 config.py 中的配置可自定义推送到不同渠道~")
|