综合实战:周报一键生成

前四节学了 Excel 处理、Word/PDF 操作、数据分析可视化、邮件消息推送。这一节把它们全部串起来------从原始数据到周报文档,从图表分析到邮件发送,一条命令搞定整个周报流程。


1. 我们要做什么

一条命令,自动完成:

scss 复制代码
原始数据(Excel) → 数据清洗 → 统计分析 → 生成图表 → 填充Word模板 → 导出PDF → 发送邮件 → 推送通知
步骤 用的技术 前几节学的
读取数据 pandas 第1节
数据清洗 pandas 第1节
统计分析 pandas + matplotlib 第3节
生成周报 python-docx 第2节
导出 PDF docx2pdf 第2节
发送邮件 smtplib 第4节
推送通知 企业微信 Webhook 第4节

2. 项目结构

bash 复制代码
weekly_report/
├── main.py              # 主入口:一键生成
├── config.py            # 配置文件
├── data/
│   └── 原始数据.xlsx     # 各部门提交的工作记录
├── templates/
│   └── 周报模板.docx      # Word 周报模板
├── output/
│   ├── 周报_20240108.docx
│   ├── 周报_20240108.pdf
│   └── charts/
│       ├── 任务完成率.png
│       └── 部门对比.png
└── requirements.txt

依赖安装

bash 复制代码
pip install pandas openpyxl matplotlib python-docx docx2pdf requests

3. 配置文件

python 复制代码
# config.py
import os
from datetime import datetime, timedelta

# ===== 路径配置 =====
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, "data")
TEMPLATE_DIR = os.path.join(BASE_DIR, "templates")
OUTPUT_DIR = os.path.join(BASE_DIR, "output")
CHART_DIR = os.path.join(OUTPUT_DIR, "charts")

# 自动创建目录
for d in [DATA_DIR, TEMPLATE_DIR, OUTPUT_DIR, CHART_DIR]:
    os.makedirs(d, exist_ok=True)

# ===== 邮件配置 =====
SMTP_SERVER = "smtp.qq.com"
SMTP_PORT = 465
SENDER_EMAIL = "your_email@qq.com"
EMAIL_PASSWORD = "your_auth_code"

# 收件人
REPORT_RECIPIENTS = [
    "boss@company.com",
    "manager@company.com",
]

# ===== 企业微信配置 =====
WECHAT_WEBHOOK = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"

# ===== 日期计算 =====
TODAY = datetime.now()
LAST_MONDAY = TODAY - timedelta(days=TODAY.weekday() + 7)
LAST_FRIDAY = LAST_MONDAY + timedelta(days=4)
WEEK_RANGE = f"{LAST_MONDAY.strftime('%m月%d日')}-{LAST_FRIDAY.strftime('%m月%d日')}"
REPORT_DATE = LAST_FRIDAY.strftime("%Y%m%d")

4. 第一步:数据读取与清洗

python 复制代码
# data_processor.py
import pandas as pd
from config import DATA_DIR, WEEK_RANGE

def load_and_clean_data():
    """读取原始数据并清洗"""
    print(f"📊 正在读取数据...")

    # 读取原始数据
    df = pd.read_excel(f"{DATA_DIR}/原始数据.xlsx")

    # 数据清洗
    # 1. 删除空行
    df = df.dropna(subset=["姓名", "部门"])

    # 2. 去重
    df = df.drop_duplicates(subset=["姓名", "任务名称", "日期"])

    # 3. 字符串清洗
    df["姓名"] = df["姓名"].str.strip()
    df["部门"] = df["部门"].str.strip()
    df["任务名称"] = df["任务名称"].str.strip()

    # 4. 日期处理
    df["日期"] = pd.to_datetime(df["日期"])

    # 5. 状态标准化
    status_map = {"已完成": "完成", "完成": "完成", "done": "完成"}
    df["状态"] = df["状态"].replace(status_map)

    # 6. 添加优先级标记
    df["是否超时"] = df["状态"].apply(
        lambda x: "超时" if x != "完成" else "正常"
    )

    print(f"  共 {len(df)} 条记录, {df['部门'].nunique()} 个部门")
    return df

5. 第二步:统计分析

python 复制代码
# analyzer.py
import pandas as pd

def analyze_data(df):
    """统计分析"""
    print("📈 正在分析数据...")

    # 部门汇总
    dept_summary = df.groupby("部门").agg(
        总任务数=("任务名称", "count"),
        完成数=("状态", lambda x: (x == "完成").sum()),
        超时数=("是否超时", lambda x: (x == "超时").sum()),
        参与人数=("姓名", "nunique"),
    ).reset_index()

    dept_summary["完成率"] = (
        (dept_summary["完成数"] / dept_summary["总任务数"] * 100)
        .round(1).astype(str) + "%"
    )

    # 人员排名
    person_summary = df.groupby(["部门", "姓名"]).agg(
        任务数=("任务名称", "count"),
        完成数=("状态", lambda x: (x == "完成").sum()),
    ).reset_index()
    person_summary["完成率"] = (
        (person_summary["完成数"] / person_summary["任务数"] * 100)
        .round(1).astype(str) + "%"
    )
    person_summary = person_summary.sort_values(
        ["部门", "任务数"], ascending=[True, False]
    )

    # 超时任务清单
    overdue = df[df["是否超时"] == "超时"][
        ["部门", "姓名", "任务名称", "日期", "状态"]
    ].sort_values("部门")

    print(f"  部门汇总: {len(dept_summary)} 行")
    print(f"  人员明细: {len(person_summary)} 行")
    print(f"  超时任务: {len(overdue)} 条")

    return dept_summary, person_summary, overdue

6. 第三步:生成图表

python 复制代码
# chart_generator.py
import matplotlib
matplotlib.use("Agg")  # 无界面模式
import matplotlib.pyplot as plt
from config import CHART_DIR, REPORT_DATE

# 设置中文字体
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False

def generate_charts(dept_summary):
    """生成统计图表"""
    print("🎨 正在生成图表...")

    charts = {}

    # 图1:部门任务完成率柱状图
    fig, ax = plt.subplots(figsize=(8, 4))
    rates = dept_summary["完成率"].str.rstrip("%").astype(float)
    bars = ax.bar(dept_summary["部门"], rates, color="#366092")

    # 颜色标记
    for bar, rate in zip(bars, rates):
        if rate >= 80:
            bar.set_color("#4CAF50")
        elif rate >= 60:
            bar.set_color("#FF9800")
        else:
            bar.set_color("#F44336")

    ax.set_ylabel("完成率 (%)")
    ax.set_title("各部门任务完成率", fontsize=14, fontweight="bold")
    ax.set_ylim(0, 105)

    for bar, rate in zip(bars, rates):
        ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 1,
                f"{rate}%", ha="center", va="bottom")

    chart_path = f"{CHART_DIR}/完成率_{REPORT_DATE}.png"
    plt.savefig(chart_path, dpi=150, bbox_inches="tight")
    plt.close()
    charts["completion"] = chart_path

    # 图2:任务分布饼图
    fig, ax = plt.subplots(figsize=(6, 6))
    ax.pie(
        dept_summary["总任务数"],
        labels=dept_summary["部门"],
        autopct="%1.1f%%",
        colors=["#366092", "#4CAF50", "#FF9800", "#9C27B0", "#F44336"],
        startangle=90
    )
    ax.set_title("各部门任务分布", fontsize=14, fontweight="bold")

    chart_path = f"{CHART_DIR}/任务分布_{REPORT_DATE}.png"
    plt.savefig(chart_path, dpi=150, bbox_inches="tight")
    plt.close()
    charts["distribution"] = chart_path

    print(f"  已生成 {len(charts)} 张图表")
    return charts

7. 第四步:生成 Word 周报

python 复制代码
# report_generator.py
from docx import Document
from docx.shared import Inches, Pt, Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH
from config import OUTPUT_DIR, REPORT_DATE, WEEK_RANGE

def generate_report(dept_summary, person_summary, overdue, charts):
    """生成 Word 周报"""
    print("📝 正在生成周报...")

    doc = Document()

    # 标题
    title = doc.add_heading(f"工作周报 ({WEEK_RANGE})", level=0)
    title.alignment = WD_ALIGN_PARAGRAPH.CENTER

    doc.add_paragraph("")  # 空行

    # 一、总体概况
    doc.add_heading("一、总体概况", level=1)
    total_tasks = int(dept_summary["总任务数"].sum())
    total_done = int(dept_summary["完成数"].sum())
    total_overdue = int(dept_summary["超时数"].sum())
    overall_rate = round(total_done / total_tasks * 100, 1) if total_tasks else 0

    doc.add_paragraph(f"本周共完成任务 {total_tasks} 项,"
                      f"已完成 {total_done} 项,"
                      f"超时 {total_overdue} 项,"
                      f"整体完成率 {overall_rate}%。")

    # 二、部门汇总表
    doc.add_heading("二、部门汇总", level=1)
    table = doc.add_table(rows=1, cols=6, style="Table Grid")
    headers = table.rows[0].cells
    headers[0].text = "部门"
    headers[1].text = "总任务"
    headers[2].text = "已完成"
    headers[3].text = "超时"
    headers[4].text = "参与人数"
    headers[5].text = "完成率"

    for _, row in dept_summary.iterrows():
        cells = table.add_row().cells
        cells[0].text = str(row["部门"])
        cells[1].text = str(int(row["总任务数"]))
        cells[2].text = str(int(row["完成数"]))
        cells[3].text = str(int(row["超时数"]))
        cells[4].text = str(int(row["参与人数"]))
        cells[5].text = str(row["完成率"])

    # 三、图表分析
    doc.add_heading("三、图表分析", level=1)
    doc.add_paragraph("各部门任务完成率:")
    doc.add_picture(charts["completion"], width=Inches(5.5))

    doc.add_paragraph("")
    doc.add_paragraph("各部门任务分布:")
    doc.add_picture(charts["distribution"], width=Inches(4.5))

    # 四、人员明细
    doc.add_heading("四、人员明细", level=1)
    table2 = doc.add_table(rows=1, cols=4, style="Table Grid")
    headers2 = table2.rows[0].cells
    headers2[0].text = "部门"
    headers2[1].text = "姓名"
    headers2[2].text = "任务数"
    headers2[3].text = "完成率"

    for _, row in person_summary.iterrows():
        cells = table2.add_row().cells
        cells[0].text = str(row["部门"])
        cells[1].text = str(row["姓名"])
        cells[2].text = str(int(row["任务数"]))
        cells[3].text = str(row["完成率"])

    # 五、超时任务
    if len(overdue) > 0:
        doc.add_heading("五、超时任务清单", level=1)
        table3 = doc.add_table(rows=1, cols=4, style="Table Grid")
        headers3 = table3.rows[0].cells
        headers3[0].text = "部门"
        headers3[1].text = "姓名"
        headers3[2].text = "任务名称"
        headers3[3].text = "状态"

        for _, row in overdue.iterrows():
            cells = table3.add_row().cells
            cells[0].text = str(row["部门"])
            cells[1].text = str(row["姓名"])
            cells[2].text = str(row["任务名称"])
            cells[3].text = str(row["状态"])

    # 保存
    output_path = f"{OUTPUT_DIR}/周报_{REPORT_DATE}.docx"
    doc.save(output_path)
    print(f"  周报已保存: {output_path}")
    return output_path

8. 第五步:导出 PDF 并发送

python 复制代码
# sender.py
import smtplib
import requests
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import os
from config import *

def export_pdf(docx_path):
    """导出 PDF"""
    print("📄 正在导出 PDF...")
    try:
        from docx2pdf import convert
        pdf_path = docx_path.replace(".docx", ".pdf")
        convert(docx_path, pdf_path)
        print(f"  PDF 已保存: {pdf_path}")
        return pdf_path
    except Exception as e:
        print(f"  ⚠️ PDF 导出失败: {e}")
        return None

def send_report_email(docx_path, pdf_path, summary_text):
    """发送周报邮件"""
    print("📧 正在发送邮件...")

    msg = MIMEMultipart()
    msg["From"] = SENDER_EMAIL
    msg["To"] = ", ".join(REPORT_RECIPIENTS)
    msg["Subject"] = f"工作周报 ({WEEK_RANGE})"

    # HTML 正文
    html = f"""
    <div style="font-family: 'Microsoft YaHei'; max-width: 600px;">
        <h2 style="color: #366092;">工作周报 ({WEEK_RANGE})</h2>
        <pre style="background: #f5f5f5; padding: 15px; border-radius: 5px;
                    font-size: 14px; line-height: 1.6;">{summary_text}</pre>
        <p>详细周报见附件(Word + PDF)。</p>
        <p style="color: #999; font-size: 12px;">此邮件由周报系统自动发送</p>
    </div>
    """
    msg.attach(MIMEText(html, "html", "utf-8"))

    # 附件
    for file_path in [docx_path, pdf_path]:
        if file_path and os.path.exists(file_path):
            with open(file_path, "rb") as f:
                attachment = MIMEApplication(f.read())
            attachment.add_header(
                "Content-Disposition", "attachment",
                filename=os.path.basename(file_path)
            )
            msg.attach(attachment)

    # 发送
    with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server:
        server.login(SENDER_EMAIL, EMAIL_PASSWORD)
        server.sendmail(SENDER_EMAIL, REPORT_RECIPIENTS, msg.as_string())

    print(f"  邮件已发送至 {len(REPORT_RECIPIENTS)} 人")

def send_wechat_notification(summary_text):
    """企业微信通知"""
    print("💬 正在推送企业微信...")

    data = {
        "msgtype": "markdown",
        "markdown": {"content": summary_text}
    }
    resp = requests.post(WECHAT_WEBHOOK, json=data)

    if resp.json().get("errcode") == 0:
        print("  企业微信通知已推送")
    else:
        print(f"  ⚠️ 推送失败: {resp.json()}")

9. 主入口:一键执行

python 复制代码
# main.py
"""
周报一键生成系统
一条命令完成:数据读取 → 清洗 → 分析 → 图表 → Word → PDF → 邮件 → 通知
"""
from config import WEEK_RANGE
from data_processor import load_and_clean_data
from analyzer import analyze_data
from chart_generator import generate_charts
from report_generator import generate_report
from sender import export_pdf, send_report_email, send_wechat_notification

def main():
    print("=" * 50)
    print(f"  周报自动生成系统")
    print(f"  报告周期: {WEEK_RANGE}")
    print("=" * 50)
    print()

    # 1. 读取数据
    df = load_and_clean_data()

    # 2. 统计分析
    dept_summary, person_summary, overdue = analyze_data(df)

    # 3. 生成图表
    charts = generate_charts(dept_summary)

    # 4. 生成 Word 周报
    docx_path = generate_report(dept_summary, person_summary, overdue, charts)

    # 5. 导出 PDF
    pdf_path = export_pdf(docx_path)

    # 6. 生成摘要文本
    total = int(dept_summary["总任务数"].sum())
    done = int(dept_summary["完成数"].sum())
    rate = round(done / total * 100, 1) if total else 0
    summary = f"""
📊 周报摘要 ({WEEK_RANGE})

总任务数: {total}
已完成: {done}
超时: {int(dept_summary['超时数'].sum())}
整体完成率: {rate}%

各部门完成率:
{dept_summary[['部门', '完成率']].to_string(index=False)}

详细周报已发送至邮箱,请注意查收。
"""

    # 7. 发送邮件
    send_report_email(docx_path, pdf_path, summary)

    # 8. 推送企业微信
    send_wechat_notification(summary)

    print()
    print("=" * 50)
    print("  ✅ 周报生成并发送完成!")
    print(f"  文件位置: {docx_path}")
    print("=" * 50)

if __name__ == "__main__":
    main()

运行效果

erlang 复制代码
==================================================
  周报自动生成系统
  报告周期: 01月01日-01月05日
==================================================

📊 正在读取数据...
  共 86 条记录, 4 个部门
📈 正在分析数据...
  部门汇总: 4 行
  人员明细: 23 行
  超时任务: 7 条
🎨 正在生成图表...
  已生成 2 张图表
📝 正在生成周报...
  周报已保存: output/周报_20240105.docx
📄 正在导出 PDF...
  PDF 已保存: output/周报_20240105.pdf
📧 正在发送邮件...
  邮件已发送至 2 人
💬 正在推送企业微信...
  企业微信通知已推送

==================================================
  ✅ 周报生成并发送完成!
==================================================

10. 结合 WorkBuddy 定时自动执行

创建 Skill

将整个周报系统封装为 WorkBuddy Skill:

yaml 复制代码
# ~/.workbuddy/skills/weekly-report/SKILL.md
---
name: weekly-report
description: 一键生成并发送工作周报
version: 1.0.0
---

# 周报自动生成技能

## 使用方式
用户说"生成周报"时执行:

1. 运行 `python main.py`
2. 如果报错,检查数据文件是否存在
3. 成功后告知用户周报已发送

## 依赖
- Python 3.10+
- pandas, openpyxl, matplotlib, python-docx, docx2pdf, requests
- 邮箱 SMTP 授权码
- 企业微信 Webhook Key

设置定时自动化

复制代码
自动化名称:每周周报自动生成
执行时间:每周五 17:30
执行内容:运行周报生成技能,自动读取数据、生成报告、发送邮件

这样每周五下班前,周报自动生成并发送,再也不用手动整理了。


回顾:五节系列总结

节次 主题 核心能力
第1节 Excel 自动化 数据读写、清洗、格式化、批量处理
第2节 Word/PDF 文档处理 模板填充、PDF 读取、格式转换
第3节 数据分析与可视化 统计分析、图表生成、分析报告
第4节 邮件与消息自动化 邮件发送、模板批量、企业消息推送
第5节 综合实战 全流程串联、一键生成、定时执行

学习建议

  1. 先跑通再优化:把示例代码跑起来,再根据实际需求调整
  2. 数据格式统一:让各部门用统一模板提交数据,减少清洗工作
  3. 模板分离:配置和模板独立文件,方便维护修改
  4. 日志记录:加日志模块,出问题时方便排查
  5. 错误处理:邮件发送失败、文件不存在等情况要 try-catch
  6. 逐步自动化:先手动触发,稳定后再加定时任务

💡 核心思想:办公自动化不是一步到位的,而是把日常重复操作逐步用脚本替代。每替代一个操作,就多出一点时间做更有价值的事。


📺 系列文章: 智能办公自动化

  • 第1节:Excel 自动化(已发布)
  • 第2节:Word/PDF 文档处理(已发布)
  • 第3节:数据分析与可视化(已发布)
  • 第4节:邮件与消息自动化(已发布)
  • 第5节:综合实战:周报一键生成(本文)
相关推荐
小二·1 小时前
国产大模型部署实战:DeepSeek + vLLM本地化推理,API成本降低90%
大数据·人工智能
fpcc3 小时前
AI和大模型——扩展模型
人工智能
xixingzhe28 小时前
AI 自然语言转SQL
人工智能
love530love8 小时前
【笔记】AutoClaw NSIS 安装器卡死、进程杀不掉、目录删不了?我是这么解决的
人工智能·windows·笔记·agent
Mandy的名字被占用了8 小时前
晨风AI+知识付费系统|学练考全闭环,重构教育变现新模式
人工智能·后端
步步为营DotNet9 小时前
Avalonia 11.3 本地离线AI图像识别绑定Minimal API AI推理网关
人工智能
满怀冰雪9 小时前
06-自动微分入门:用 Paddle 计算梯度
人工智能·python·深度学习·paddle
架构源启9 小时前
文档接入与智能解析:基于 Spring AI 1.1.x 的多格式解析、版面理解与结构化抽取
java·人工智能·spring
李昊哲小课9 小时前
GLM 多技术栈集成完整教程
人工智能·智能体
浩哥学JavaAI10 小时前
2026年最新AI agent面试(10)_通信与行业动态
人工智能·面试·职场和发展