返回 Skill 列表
extension
分类: 数据与分析需要 API Key

QA周报

QA周报自动生成技能。当用户需要读取采购云QA报告邮件、解析Excel附件、生成HTML数据分析报告时,使用此技能。 触发词:QA报告、采购云报告、生成周报、读取QA邮件、质量报告、迭代进度报告、QA数据分析、生成采购云HTML报告、 评审统计报告、缺陷分析报告、迭代报告。 本技能封装了完整的邮件读取、附件下载、Excel解析、HTML报告生成全流程,并支持与上周数据对比。

person作者: user_6cfa0699hubcommunity

采购云 QA 周报自动生成技能

技能简介

本技能封装了采购云产品部 QA 周报的完整生成流程,包括:

  1. 通过 IMAP 协议读取指定邮件及下载 Excel 附件
  2. 解析多张 Excel 工作表数据
  3. 自动与上周数据对比
  4. 生成结构化 HTML 数据分析报告(含每节分析说明)
  5. 将 HTML 报告截图导出为 PNG 图片

配置前提

邮箱连接信息存储在工作区根目录的 mail_config.json,格式如下:

{
  "host": "mail.yonyou.com",
  "port": 993,
  "email": "chengmingm@yonyou.com",
  "password": "授权码"
}

注意:需在公司内网环境下运行,服务器 mail.yonyou.com 为内网地址(10.16.16.x)。

工作流程

Phase 1:读取目标邮件

  1. 读取 mail_config.json 获取连接信息
  2. 通过 IMAP SSL 连接邮件服务器
  3. 在所有文件夹中搜索主题含"采购云QA报告"、日期匹配的邮件
  4. 下载全部 Excel 附件到工作区(命名格式保持原始文件名)
  5. 同时搜索上一周的 QA 报告邮件,下载附件并加 lastweek_ 前缀

使用脚本:scripts/fetch_email.py

Phase 2:解析 Excel 数据

解析以下工作表(文件名与 Sheet 名可能不同,按实际内容匹配):

| 文件/Sheet 名 | 内容说明 | |---|---| | 产品+组织 | 各三级目标有效特性数、开发/测试完成率 | | 评审统计-按组织 | 各评审项计划数、关闭率、及时率 | | 评审计划明细表 | 全部未关闭评审明细 | | 报表1 | 本周计划评审明细(含未及时标识) | | 迭代进度 | 各迭代各组织故事总数、提测率、完成率 | | 缺陷处理中-按部门 | 515未关闭缺陷,按版本统计开发/测试未完成数 | | 承诺解决-按二级组织 | 承诺需求数量,关注公有云处理中 | | 09-预警明细 | 承诺需求预警明细 | | 采购云-提出待分析 | 协作需求(采购云作为提出方,协作方未分析) | | 采购云-协作待分析 | 协作需求(采购云作为协作方,需分析) | | 需求处理情况 | 原始需求的处理情况明细 | | 支持问题按客户-一级组织 | 支持问题按客户/一级组织统计,含提出问题数量 | | 含类型-按二级 | 支持问题首次响应耗时分析,按二级分类统计(整合进第7节7.2子节) | | 处理中-按一二三级业务组织 | 支持问题处理中结存数量(本周从邮件附件获取),用于第7.3节趋势折线图 | | 处理中结存历史(pending_history.json) | 所有历史周的处理中结存数据,持久化存储。脚本自动追加当前周数据,图表展示全部历史周期,表格仅展示近三周。历史数据缺失时可从往期报告HTML中提取补全 |

使用脚本:scripts/parse_excel.py(输出 all_data.json,包含本周和上周所有Excel数据的 current/previous 双份数据)

Phase 3:读取邮件正文

从邮件正文中提取:

  • 整体趋势分析链接(URL)
  • 按客户提出统计的前10名客户信息
  • 其他补充文字内容

使用脚本:scripts/fetch_email.py(同步输出 qa_email_content.json

Phase 4:生成 HTML 报告

🔒 样式锁定:必须以 采购云QA报告-20260426.html 为唯一样式基准。

📦 额外依赖:第7.3节折线图使用 Chart.js,需在 <head> 中引入 CDN:

<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>

报告结构:12 个专题 + 7.3 子节(已去掉旧版第13/14/15节:支持问题按客户独立节、首次响应耗时独立节、上线后工单分析节;相关内容已整合入第7节子节)

所有生成的报告在 HTML 结构、CSS 样式、布局格式、组件类名上,必须与基准文件 完全一致。具体规范详见 references/report_template_guide.md(该文档已从 0426 基准文件中完整提取)。

参考 references/report_template_guide.md 中的报告结构规范,生成完整 HTML 文件。

必须包含的12个专题,每个专题结构为:

标题(section-title)
  ↓
分析说明框(info-box,放置在标题正下方、表格之前)
  ↓
数据表格(部分专题不输出表格,见各专题说明)
  ↓
结论框(warn-box / ok-box)

各专题核心要求:

  1. 产品+组织不输出数据表格,只输出分析文字,结构如下:
    • 总量变化:本周有效特性数总数较上周变化(增/减/持平),整体开发完成率、测试通过率、特性发布率及较上周变化
    • 三级目标特性变化:列表格式,减少项红色数字标注,新增项蓝色 NEW 标签,按变动值排序
    • 有效特性数为0的三级目标:⚠️ 红色警告列出所有零特性目标
    • 底部总结:✅ 绿色成功框总结
    • 标题标签使用 tag info "总览"
  2. 评审统计-按组织 — 含两个对比子模块:
    • 各评审项计划数对比表:评审项 / 上周评审计划数 / 本周评审计划数 / 增加数(↑+X / ↓X / →0)
    • 环比分析框:蓝色 info-box,评审计划总数较上周变化 + 评审关闭率较上周变化(含百分点)
    • 完整明细表:表格新增"较上周"列,每行显示评审计划数增减;关闭率/及时率带颜色标记
  3. 评审计划明细表 — 保留全部未关闭评审,超期行标红
  4. 报表1 — 保留全部明细,未及时评审行标红
  5. 迭代进度 — 按迭代分组展示(跳过已上线的迭代,如 20260615),每组包含提测率、测试完成率等关键指标:
    • 分析规则由用户在使用技能时提供,每次执行时根据用户给出的规则进行数据分析
    • 数据表格和结构保持不变,仅分析逻辑/关注点/判断标准由用户提供
    • 每个迭代块包含:iter-head 标题 + 分析说明 + 末级组织达标/未达标表格 + 结论框
  6. 缺陷处理中-按部门不输出数据表格,只输出分析文字,分析内容包含以下两部分:
    • 分析规则由用户在使用技能时提供,每次执行时根据用户给出的规则进行数据分析
    • 两部分分析内容的具体关注点、判断标准和表达方式均以用户提供的规则为准
  7. 支持问题整体 — 该节包含三个子节,全部在同一个 <div class="section"> 容器内:
    • 7.1 支持问题整体趋势:分析本周新增/关闭/未关闭支持问题数量及与上周对比,保留按客户提出前10名表格
    • 7.2 支持问题首次响应耗时分析:来源于 含类型-按二级.xlsx不输出表格,纯文字,只列出平均首次响应时长 >10小时 的部门与问题类型(含问题数量和平均时长),按时长从高到低排序
    • 7.3 支持问题处理中结存情况:来源于邮件附件 处理中-按一二三级业务组织.xlsx + pending_history.json 历史数据,输出:
      • 采购云处理中支持问题总数,各部门处理中支持问题数,按从多到少排列,标注与上周对比变化量
      • Chart.js 折线图:展示全部历史周期(如 0614 / 0621 / 0628 / 0705 / 本周0712)各部门结存趋势,X轴为日期,Y轴为结存数量,每条部门线一种颜色,不含合计线,鼠标悬停显示数值,底部有图例
      • 明细表格:仅展示近三周数据(如 0628 / 0705 / 本周),本周列高亮蓝色,含"较上周变动"列
  8. 承诺解决-按二级组织 — 关注公有云处理中的待规划和实现中数量
  9. 09-预警明细 — 保留完整明细
  10. 采购云-提出待分析 — 标签 tag warn "待处理",展示提出待分析数量和较上周对比。若数据为空(含仅URL模板的占位行)则显示"暂无",表格列精简(9列:协作方组织/产品/级次/分析人/提出方组织/提出方产品/提出人/协作需求编码→查看链接/期望时间)。有数据时底部 ⚠️ 红色警告框提示及时处理。空数据检测:需过滤以 https://pm.yyrd.com/https://gfjira.yyrd.com/ 开头的URL模板占位值,仅当行中存在非URL模板的有效数据时才视为有数据。
  11. 采购云-协作待分析 — 标签 tag ok "协作",展示协作待分析数量和较上周对比。表格 10列(在提出待分析9列基础上增加"协作需求名称"列,截断50字),无警告框。
  12. 需求处理情况 — 标签 tag info "汇总",不输出数据表格,只输出分析文字
  • 原始需求总数(较上周变化)、已处理数、及时处理率(含上周对比)
  • 待分析待规划数量及占比
  • 大于1个月的待分析待规划个数(含上周对比)
  • 底部 💡 蓝色提示框

7.3 节实现指南(支持问题处理中结存)

数据来源与持久化:

  • 本周:邮件附件中的 处理中-按一二三级业务组织.xlsx(Row1=合计,Row2+=各部门)
  • 历史:pending_history.json(工作区根目录),持久化存储所有历史周数据
  • Excel 结构:col1=部门名称,col2=处理中数量;Row1 通常为合计行,部门名称为"采购云合计"
  • 历史数据缺失补全:若 pending_history.json 中缺少某周数据,可从往期报告HTML的7.3节明细表格中提取(表头含"MMDD结存"列,合计行有 <tr class="total-row">

pending_history.json 格式:

{
  "weeks": [
    {
      "week": "0614",
      "total": 143,
      "depts": {
        "供应链协同开发部": 42,
        "采购寻源开发部": 34,
        "供应商关系管理开发部": 32,
        "招投标与超市开发部": 28,
        "采购云公共与数智开发部": 6
      }
    }
  ]
}

核心逻辑:

  1. 读取 pending_history.json 获取所有历史周数据
  2. 解析本周 处理中-按一二三级业务组织.xlsx 获取当前周数据
  3. 将当前周数据追加到历史(如已存在同周码则更新),按周码排序后保存回 pending_history.json
  4. 图表:展示全部历史周(所有 history_weeks),每条部门线一种颜色,不含合计线
  5. 表格:仅展示最近三周(history_weeks[-3:]),本周列高亮,含"较上周变动"列

解析函数(openpyxl):

def parse_pending_dept(filepath, label):
    """解析处理中Excel,返回 (total, [{org, count}])"""
    wb = openpyxl.load_workbook(filepath, data_only=True)
    ws = wb.active
    total = int(float(ws.cell(1, 2).value or 0))
    depts = []
    for r in range(2, ws.max_row + 1):
        org = ws.cell(r, 1).value
        cnt = ws.cell(r, 2).value
        if org and cnt:
            depts.append({'org': str(org).strip(), 'count': int(float(cnt))})
    wb.close()
    return total, depts

历史数据追加与持久化:

HISTORY_PATH = 'd:/Download/cunchu/pending_history.json'
report_week_label = '0712'  # 每次修改为当前周码

# 读取历史
try:
    with open(HISTORY_PATH, 'r', encoding='utf-8') as f:
        pending_history = json.load(f)
except FileNotFoundError:
    pending_history = {'weeks': []}

history_weeks = pending_history.get('weeks', [])
cur_depts_map = {d['org']: d['count'] for d in cur_depts}
current_week_entry = {
    'week': report_week_label,
    'total': cur_total,
    'depts': cur_depts_map
}
# 已存在则更新,不存在则追加
existing_idx = next((i for i, w in enumerate(history_weeks) if w.get('week') == report_week_label), None)
if existing_idx is not None:
    history_weeks[existing_idx] = current_week_entry
else:
    history_weeks.append(current_week_entry)
history_weeks.sort(key=lambda w: w['week'])

# 保存
with open(HISTORY_PATH, 'w', encoding='utf-8') as f:
    json.dump(pending_history, f, ensure_ascii=False, indent=2)

图表与表格分离构建:

chart_depts = ['供应链协同开发部', '供应商关系管理开发部', '招投标与超市开发部', '采购寻源开发部', '采购云公共与数智开发部']
chart_colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6']

# 图表:全部历史周
history_labels = [w['week'] for w in history_weeks]
display_labels = [f"本周{w}" if w == report_week_label else w for w in history_labels]

chart_datasets = ''
for i, dept in enumerate(chart_depts):
    data_vals = [w['depts'].get(dept, 0) for w in history_weeks]
    data_str = ', '.join(str(v) for v in data_vals)
    chart_datasets += f"""{{
        label: "{dept}",
        data: [{data_str}],
        borderColor: "{chart_colors[i]}",
        backgroundColor: "{chart_colors[i]}11",
        borderWidth: 2,
        tension: 0.3,
        pointRadius: 4,
        pointHoverRadius: 6,
    }},"""

# 表格:仅最近三周
table_weeks = history_weeks[-3:]
table_labels = [w['week'] for w in table_weeks]
header_cols = ''
for w in table_labels:
    header_cols += '<th>本周结存</th>' if w == report_week_label else f'<th>{w}结存</th>'

# 趋势链文字:全部历史周
trend_chain = ' → '.join(
    f'<strong>{display_labels[i]}</strong>期 <strong>{history_weeks[i]["total"]}</strong>'
    for i in range(len(history_weeks))
)

Chart.js 折线图实现要点:

  • 在 HTML <head> 中通过 CDN 引入:<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
  • 使用 <canvas id="pending_chart"> 作为图表容器
  • X 轴为日期标签(如 ["0614", "0621", "0628", "0705", "本周0712"]),Y 轴为结存数量
  • 每条部门线一种颜色(5个部门,无合计线)
  • 使用 new Chart(ctx, { type: 'line', data: {...}, options: {...} }) 渲染
  • 图表 init 脚本放在 window.onload 中,或使用 DOMContentLoaded 事件

图表配置关键参数:

const chartColors = [
    '#e74c3c',  // 红 - 供应链协同开发部
    '#3498db',  // 蓝 - 供应商关系管理开发部
    '#2ecc71',  // 绿 - 招投标与超市开发部
    '#f39c12',  // 橙 - 采购寻源开发部
    '#9b59b6',  // 紫 - 采购云公共与数智开发部
];
// 注意:不再包含合计线

options: {
    responsive: true,
    maintainAspectRatio: false,
    plugins: {
        legend: { position: 'bottom', labels: { padding: 16, usePointStyle: true, pointStyleWidth: 10, font: { size: 12 } } },
        tooltip: { callbacks: { label: function(ctx) { return ctx.dataset.label + ": " + ctx.parsed.y + " 个"; } } }
    },
    scales: {
        y: { beginAtZero: true, title: { display: true, text: "处理中数量(个)" }, ticks: { stepSize: 10 } },
        x: { title: { display: true, text: "统计周期" } }
    }
}

第7.3节完整 HTML 结构:

<div class="section" style="border-left: 4px solid #6f42c1;">
  <div class="section-title">📋 7.3 支持问题处理中结存情况<span class="tag info">趋势对比</span></div>
  <div class="info-box">
    <strong>分析:</strong>采购云处理中支持问题总数:0614期 143 → 0621期 149 → ... → 本周0712期 155(较上周 ↑+39)。
    本周各部门处理中结存按从多到少排列:...
  </div>

  <div style="font-weight:600;color:#1a6fc4;margin:14px 0 8px">处理中结存趋势对比</div>
  <div style="position:relative;width:100%;max-width:900px;margin:0 auto 16px;background:#fff;border:1px solid #e0e0e0;border-radius:8px;padding:16px;">
    <canvas id="pending_chart" style="width:100%;height:380px;"></canvas>
  </div>
  <script>
  (function() {
    var ctx = document.getElementById("pending_chart").getContext("2d");
    new Chart(ctx, {
      type: "line",
      data: { labels: [...], datasets: [...] },
      options: { ... }
    });
  })();
  </script>

  <div style="font-weight:600;color:#1a6fc4;margin:10px 0 6px">各部门结存明细</div>
  <div class="table-wrap">
    <table>
      <thead><tr><th>排名</th><th>部门</th><th>0628结存</th><th>0705结存</th><th>本周结存</th><th>较上周变动</th></tr></thead>
      <tbody>
        <tr class="total-row"><td></td><td>合计</td><td>125</td><td>116</td><td style="font-weight:600;color:#1a6fc4">155</td><td>↑+39</td></tr>
        <!-- 各部门行,按本周结存从多到少 -->
      </tbody>
    </table>
  </div>
</div>

注意: 图表初始化脚本必须放在 {sec7_3} 变量之后、页面底部之前,使用独立的 <script> 标签。

输出文件:采购云QA报告-YYYYMMDD.html

样式基准: 采购云QA报告-20260426.html(固定不变) 模板规范: references/report_template_guide.md(从基准文件提取的完整规范)

Phase 5:截图导出 PNG

将 HTML 报告截图导出为全页 PNG 图片。使用 Node.js playwright(非 Python playwright,因托管 Python 环境下 pip install playwright 可能卡死)。

前置条件:

  • Chromium headless shell 已安装于 %LOCALAPPDATA%/ms-playwright/chromium_headless_shell-1224/
  • Node.js playwright 包已可用(npm 全局或本地)

截图脚本模板 screenshot_report.js(放在工作区根目录):

const { chromium } = require('playwright');
const path = require('path');
const fs = require('fs');

// ⚠️ 每次使用时按实际日期修改文件名
const htmlPath = path.resolve('d:/Download/cunchu/采购云QA报告-YYYYMMDD.html');
const outputPath = path.resolve('d:/Download/cunchu/采购云QA报告-YYYYMMDD.png');
const fileUrl = 'file:///' + htmlPath.replace(/\\/g, '/');

(async () => {
  // ⚠️ 必须指定 executablePath:Node playwright 版本期望 chromium-1217,
  // 但实际已安装 chromium_headless_shell-1224,不指定会报错找不到浏览器
  const exePath = process.env.LOCALAPPDATA + '/ms-playwright/chromium_headless_shell-1224/chrome-headless-shell-win64/chrome-headless-shell.exe';
  const browser = await chromium.launch({ headless: true, executablePath: exePath });
  const page = await browser.newPage({ viewport: { width: 1400, height: 900 } });
  await page.goto(fileUrl, { waitUntil: 'networkidle' });
  await page.screenshot({ path: outputPath, fullPage: true });
  await browser.close();

  const size = fs.statSync(outputPath).size / 1024;
  console.log(`✅ 截图已保存: ${outputPath}`);
  console.log(`   大小: ${size.toFixed(1)} KB`);
})();

运行命令:

cd /d/Download/cunchu && /c/Users/wojia/.workbuddy/binaries/node/versions/22.12.0/node.exe screenshot_report.js

常见问题:

  • 若报 Executable doesn't exist at ... chromium_headless_shell-1217:确认脚本中 executablePath 指向正确的 chromium_headless_shell-1224 路径
  • 若报 Cannot find module 'playwright':运行 npm install playwright 安装

使用示例

读取邮件 chengmingm@yonyou.com 中主题为"采购云QA报告"、
收件时间 2026-04-19 14:05 的邮件,依照附件和邮件内容生成HTML报告

注意事项

  • Excel 文件编码统一使用 utf-8,读取时用 openpyxl 引擎
  • Windows 环境下脚本需用 py -X utf8 script.py 运行,避免 emoji 编码问题
  • $ 字符在密码中需写入 JSON 文件,避免 PowerShell 解析错误
  • IMAP 搜索日期格式:DD-Mon-YYYY(如 19-Apr-2026
  • 邮件可能在归档文件夹(非 INBOX),需遍历所有文件夹搜索
  • 搜索上周邮件时可用相邻 ID 定位,或按日期范围搜索
  • Chart.js CDN:第7.3节折线图依赖 Chart.js,HTML 须在 <head> 中引入 CDN 脚本
  • 处理中结存历史数据:使用 pending_history.json 持久化存储,脚本自动追加当前周数据。图表展示全部历史周期,表格仅展示近三周。历史数据缺失时可从往期报告HTML的7.3节明细表格中提取补全
  • 图表不含合计线:第7.3节折线图仅展示5个部门线,不再包含合计线
  • 处理中结存Excel结构处理中-按一二三级业务组织.xlsx 的 col1=部门名(含"采购云合计"),col2=数量
  • 提出待分析空数据检测:需过滤以 https://pm.yyrd.com/https://gfjira.yyrd.com/ 开头的URL模板占位值,仅当行中存在非URL模板的有效数据时才视为有数据
  • 迭代进度过滤:已上线的迭代(如 20260615)应从第5节中排除,仅展示进行中的迭代