禅道数据自动拉取与报表生成工具:日报周报+缺陷分析+项目进度SQL脚本合集

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:直接对接禅道MySQL数据库,用Python脚本批量跑出测试团队日常需要的各类数据报表。每天早上自动出一份日报,每周一生成周报,内容包括缺陷新增/关闭趋势、各模块缺陷分布、缺陷平均修复时长、线上问题与日常缺陷对比、项目整体进度、任务完成率、成员工作量分布等。所有分析都基于真实数据库表结构,配套SQL文件已预置好常用查询逻辑(如daily_report.sql、bug_time_summary.sql、project_detail.sql等),Python脚本支持一键执行、Excel导出(read_excel.py)、邮件自动发送(common_mail_test.py)和通用表格处理(common_deal_table.py)。脚本模块化设计,daily_report.py、weekly_report.py、bug_time_detail.py、project_summary.py等可单独运行,也可组合调用;数据库连接配置统一放在common_mysql_config.py里,改一次密码全链路生效。适配禅道8.x及以上版本,部署前只需填入MySQL地址、账号、密码和禅道数据库名,无需额外安装服务或依赖复杂中间件。适合测试负责人、质量保障工程师、研发项目经理做日常数据盯盘、迭代复盘和质量度量。

1. 项目概述:为什么我放弃了“点点点导出+Excel手工整理”的日报周报模式

三年前,我还在用禅道网页端手动筛选、导出、复制粘贴——每天早上9:15准时打开禅道,切到“缺陷”页,按“创建日期=今天”筛选,导出CSV;再切到“任务”,按“截止日期=今天”导出;再切到“项目”,查进度条……然后打开Excel,把三份表格合并、去重、加透视表、画折线图。一套操作下来,固定耗时42分钟。更糟的是,每周一的周报要回溯7天数据,得重复7次筛选动作,中间只要漏掉一天,整个趋势图就断档。有次迭代复盘会上,研发总监指着PPT里一张“缺陷修复时长趋势图”问我:“这张图里‘平均修复时长’是按‘解决时间-创建时间’算的?还是‘关闭时间-创建时间’?有没有排除已取消/已拒绝的缺陷?”我当场卡壳——因为Excel里根本没留原始字段,只存了最终结果。

这就是我启动这个工具的直接动因:不是为了炫技,而是为了把“数据搬运工”的时间,换成“质量分析者”的思考时间。 这套工具不碰禅道API(8.x之后API权限收敛严重,且需Token轮换),也不依赖任何第三方BI平台(公司不允许外传数据),而是直连禅道底层MySQL数据库——这是所有禅道部署的标配,也是最稳定、最可控的数据源。它解决的不是“能不能拿到数据”,而是“能不能在5分钟内,拿到准确、可追溯、可对比、可归因的数据”。

核心关键词“禅道报表、缺陷分析、项目进度、Python脚本、MySQL查询”背后,其实是五个刚性需求:
- 时效性:日报必须在早会前生成,周报必须在周一上午10点前发出;
- 准确性:所有统计口径必须与禅道后台逻辑一致(比如“已解决”状态是否计入“已关闭”?“延期任务”如何定义?);
- 可解释性:每张图表下方必须能点开明细表,看到每一行数据来自哪条SQL、哪个表、哪个字段;
- 低维护性:换新同事接手,30分钟内能看懂逻辑、改配置、跑通流程;
- 可扩展性:当测试经理突然说“下周开始要统计每个模块的自动化覆盖率”,我能用不到1小时新增一个module_automation_report.py,而不是重写整套框架。

它不是给程序员写的工具,而是给测试负责人、质量分析师、研发项目经理写的“数据杠杆”。你不需要懂Python语法,但需要理解“bug_time_summary.sql里AVG(TIMESTAMPDIFF(HOUR, t1.openedDate, t1.resolvedDate))”这句话意味着什么——它计算的是从缺陷创建到解决之间的平均小时数,且只统计状态为“已解决”的记录(t1.status = 'resolved')。这种“SQL即文档”的设计,让业务人员也能参与逻辑校验,而不是把黑盒脚本交给开发后就失去话语权。

2. 整体架构与模块化设计:为什么选择“SQL先行+Python胶水”的组合

这套工具的骨架,是我在拆解禅道8.5.3数据库表结构后,反复推演三个月才定型的。很多人第一反应是“为什么不直接用Python ORM(如SQLAlchemy)写查询?”,答案很实在:ORM抽象层会掩盖业务语义,而质量分析的核心恰恰在于对每一个字段含义的精确控制。

举个典型例子:禅道里一个缺陷的“解决时间”,实际存储在zt_bug表的resolvedDate字段,但它的业务含义取决于status字段——只有当status IN ('resolved', 'closed')时,resolvedDate才是有效值;如果status = 'wait'(等待中),这个时间戳就是无效的。用ORM写,很容易写出Bug.query.filter(Bug.status.in_(['resolved','closed'])).avg(Bug.resolvedDate - Bug.openedDate),看似简洁,但resolvedDate - openedDate在MySQL里是日期相减,在Python里是datetime对象运算,跨层转换极易出错,且无法利用MySQL原生的TIMESTAMPDIFF()函数做精准的小时/天级计算。而手写SQL,你可以明确写出:

SELECT 
  AVG(TIMESTAMPDIFF(HOUR, b.openedDate, b.resolvedDate)) AS avg_resolve_hour,
  COUNT(*) AS resolved_count
FROM zt_bug b 
WHERE b.status IN ('resolved', 'closed') 
  AND b.openedDate >= '2024-06-01' 
  AND b.openedDate < '2024-06-02';

这段SQL的每一行,都对应着质量度量报告里的一个关键指标,且可直接在Navicat里执行验证。这才是业务可信的起点。

因此,整个架构采用“三层洋葱模型”:
- 最内层:SQL文件(*.sql)——纯SQL语句,定义“查什么”。daily_report.sql负责日报核心指标(当日新增缺陷、关闭缺陷、进行中任务数等);bug_time_summary.sql聚焦缺陷生命周期(平均创建到解决时长、解决到关闭时长);project_detail.sql拉取项目级明细(每个项目名称、起止时间、当前进度%、剩余任务数)。这些SQL文件被当作“数据契约”来管理,每次禅道升级后,只需检查表结构变更(如zt_bug新增storyVersion字段),微调SQL即可,不影响上层Python逻辑。
- 中间层:Python脚本(*.py)——“胶水层”,定义“怎么查、查完怎么用”。common_read_sql.py负责安全读取SQL文件(自动过滤注释、处理多语句分隔);common_mysql_config.py统一管理数据库连接参数(host/port/user/password/dbname),支持环境变量覆盖,避免密码硬编码;common_deal_table.py提供通用表格处理能力(如按某列求和、按状态分组计数、生成趋势折线图所需的时间序列格式)。这一层不包含任何业务逻辑,只做数据搬运和格式转换。
- 最外层:执行脚本(daily_report.py, weekly_report.py等)——“业务接口”,定义“谁来查、查完给谁”。daily_report.py加载daily_report.sql,执行后调用read_excel.py导出为daily_20240601.xlsx,再调用common_mail_test.py发邮件;bug_time_detail.py则加载bug_time_detail.sql(该SQL返回每一条已解决缺陷的ID、创建时间、解决时间、所属模块),生成明细表供质量分析师逐条下钻分析。

这种设计带来的直接好处是:当业务需求变化时,90%的修改发生在SQL层,而非Python层。 比如,测试经理要求“日报里增加‘高优缺陷占比’(priority=1 or priority=2的缺陷数/总缺陷数)”,你只需要在daily_report.sql里加两行SELECT子句,Python脚本完全不用动。这极大降低了维护成本,也使得SQL文件可以作为团队共享的知识库——新人入职,先看懂daily_report.sql,就等于看懂了日报的全部业务规则。

提示:所有SQL文件均采用“标准命名+版本号”方式管理,如daily_report_v2.sql。v1版本只统计总数,v2版本增加了优先级分布。每次升级SQL,都在对应Python脚本头部添加注释说明变更点,例如# 2024-05-20: daily_report_v2.sql - 新增priority_distribution字段,用于计算高优缺陷占比。

3. 核心脚本解析与实操要点:从配置到执行的完整链路

3.1 数据库连接配置:common_mysql_config.py 是唯一可信源

这是整个工具链的“心脏”,所有脚本都通过它获取数据库连接。它的设计原则是:最小权限、最大隔离、零硬编码。

# common_mysql_config.py
import os
from urllib.parse import quote_plus

# 1. 优先从环境变量读取(适合Docker/K8s部署)
DB_HOST = os.getenv('ZENTAO_DB_HOST', '127.0.0.1')
DB_PORT = int(os.getenv('ZENTAO_DB_PORT', '3306'))
DB_USER = os.getenv('ZENTAO_DB_USER', 'zentao_reader')
DB_PASSWORD = quote_plus(os.getenv('ZENTAO_DB_PASSWORD', 'your_password_here'))  # 处理特殊字符
DB_NAME = os.getenv('ZENTAO_DB_NAME', 'zentao')

# 2. 其次尝试读取本地配置文件(适合开发机)
if not DB_PASSWORD or DB_PASSWORD == 'your_password_here':
    try:
        with open('config/local_db.conf', 'r', encoding='utf-8') as f:
            lines = [line.strip() for line in f if line.strip() and not line.startswith('#')]
            for line in lines:
                key, val = line.split('=', 1)
                if key.strip() == 'DB_PASSWORD':
                    DB_PASSWORD = quote_plus(val.strip().strip("'\""))
    except FileNotFoundError:
        pass

# 3. 构建连接URL(使用pymysql,兼容禅道默认字符集)
DB_URL = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}?charset=utf8mb4"

这里的关键细节:
- quote_plus()处理密码:如果密码含@或/,不转义会导致URL解析失败。我曾因密码是P@ssw0rd/2024,导致脚本一直报pymysql.err.OperationalError: (1045, "Access denied"),排查了两天才发现是URL解析问题。
- 环境变量优先:生产环境部署时,通过K8s Secret注入环境变量,彻底避免密码出现在代码或配置文件中。
- 本地配置文件兜底:开发机上,新建config/local_db.conf,内容为:
DB_HOST=192.168.1.100 DB_PORT=3306 DB_USER=ztp_reader DB_PASSWORD='My$ecur3P@ss' DB_NAME=zentao_prod
注意:单引号包裹密码,脚本会自动去除。

注意:禅道8.x默认使用utf8mb4字符集,若连接时未指定,遇到emoji或生僻字(如某些测试用例描述含中文符号)会报错。?charset=utf8mb4是必加参数。

3.2 SQL读取与执行:common_read_sql.py 如何安全加载SQL文件

common_read_sql.py是“胶水层”的核心,它解决了三个痛点:SQL注释干扰、多语句分割、参数化查询。

# common_read_sql.py
import re
import pymysql

def read_sql_file(file_path):
    """安全读取SQL文件,移除注释,分割多语句"""
    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()

    # 移除 -- 单行注释和 /* */ 多行注释
    content = re.sub(r'--.*$', '', content, flags=re.MULTILINE)
    content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)

    # 按分号分割语句,过滤空行
    statements = [stmt.strip() for stmt in content.split(';') if stmt.strip()]
    return statements

def execute_sql(conn, sql_content, params=None):
    """执行单条SQL,支持参数化查询(防SQL注入)"""
    cursor = conn.cursor()
    try:
        cursor.execute(sql_content, params or ())
        if sql_content.strip().upper().startswith('SELECT'):
            result = cursor.fetchall()
            columns = [col[0] for col in cursor.description]
            return result, columns
        else:
            conn.commit()
            return None, None
    finally:
        cursor.close()

实操中,read_sql_file()会将daily_report.sql中的:

-- 日报核心指标查询(v2)
SELECT 
  COUNT(CASE WHEN b.status = 'active' THEN 1 END) AS active_bug_count,
  COUNT(CASE WHEN b.priority IN (1,2) THEN 1 END) AS high_priority_count,
  COUNT(*) AS total_bug_count
FROM zt_bug b 
WHERE b.openedDate >= '2024-06-01' AND b.openedDate < '2024-06-02';

清洗为纯净的SELECT ... FROM ... WHERE ...;,并正确分割。而execute_sql()的params参数,让你能在Python中动态传入日期:

# 在 daily_report.py 中
start_date = '2024-06-01'
end_date = '2024-06-02'
sql = "SELECT ... WHERE b.openedDate >= %s AND b.openedDate < %s;"
result, cols = execute_sql(conn, sql, (start_date, end_date))

这比字符串拼接f"WHERE b.openedDate >= '{start_date}'"安全得多,彻底杜绝SQL注入风险。

3.3 报表生成与导出:read_excel.py 的定制化输出逻辑

read_excel.py不是简单调用pandas.to_excel(),而是针对质量报表做了深度定制:

  • 多Sheet组织:日报Excel包含Summary(汇总卡片)、Bug_Detail(当日缺陷明细)、Task_Status(任务状态分布)三个Sheet;
  • 样式强化:关键指标单元格(如“高优缺陷占比”)自动标红(>30%)或绿色(<10%);
  • 冻结窗格:Bug_Detail Sheet首行冻结,方便横向滚动查看长字段;
  • 超链接支持:缺陷ID列自动生成禅道网页链接,点击直达详情页(https://zentao.yourcompany.com/bug-view-{id}.html)。

核心代码片段:

# read_excel.py
import pandas as pd
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment

def export_to_excel(data_dict, filename):
    """
    data_dict: {sheet_name: {'data': df, 'highlight_col': 'high_priority_ratio'}}
    """
    writer = pd.ExcelWriter(filename, engine='openpyxl')

    for sheet_name, config in data_dict.items():
        df = config['data']
        df.to_excel(writer, sheet_name=sheet_name, index=False)

        # 获取工作表对象
        worksheet = writer.sheets[sheet_name]

        # 冻结首行
        worksheet.freeze_panes = 'A2'

        # 高亮指定列
        if 'highlight_col' in config:
            col_idx = df.columns.get_loc(config['highlight_col']) + 1  # Excel列索引从1开始
            for row in range(2, len(df)+2):  # 从第2行开始(第1行是标题)
                cell = worksheet.cell(row=row, column=col_idx)
                val = df.iloc[row-2][config['highlight_col']]
                if pd.notna(val):
                    if val > 0.3:
                        cell.font = Font(color="FF0000")  # 红色
                        cell.fill = PatternFill("solid", fgColor="FFEB3B")  # 浅黄底
                    elif val < 0.1:
                        cell.font = Font(color="009688")  # 青色
                        cell.fill = PatternFill("solid", fgColor="C8E6C9")  # 浅绿底

    writer.close()

这个设计让报表不再是冷冰冰的数据堆砌,而是具备交互性和可读性的分析载体。测试负责人扫一眼Summary Sheet的红色数字,就能立刻定位风险点;点击Bug_Detail里的ID,3秒直达禅道缺陷页,无需再手动复制ID去搜索。

3.4 邮件自动发送:common_mail_test.py 的企业微信/钉钉兼容方案

common_mail_test.py名字带“test”,是因为它内置了双通道:SMTP邮件(传统)和Webhook推送(现代)。很多公司已禁用内部SMTP,但允许向企业微信/钉钉机器人发消息。

# common_mail_test.py
import smtplib
import json
import requests
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def send_email(subject, body, to_emails, attachments=None):
    """发送SMTP邮件(需配置邮箱)"""
    msg = MIMEMultipart()
    msg['From'] = 'qa-report@yourcompany.com'
    msg['To'] = ', '.join(to_emails)
    msg['Subject'] = subject
    msg.attach(MIMEText(body, 'plain', 'utf-8'))

    # 添加附件
    if attachments:
        for file_path in attachments:
            with open(file_path, 'rb') as f:
                part = MIMEApplication(f.read(), Name=os.path.basename(file_path))
                part['Content-Disposition'] = f'attachment; filename="{os.path.basename(file_path)}"'
                msg.attach(part)

    server = smtplib.SMTP('smtp.yourcompany.com', 587)
    server.starttls()
    server.login('qa-report@yourcompany.com', 'app_password_here')
    server.send_message(msg)
    server.quit()

def send_webhook(title, message, webhook_url):
    """发送企业微信/钉钉Webhook(JSON格式)"""
    payload = {
        "msgtype": "markdown",
        "markdown": {
            "content": f"### {title}\n\n> {message}\n\n- 报表已生成,请查收附件。"
        }
    }
    requests.post(webhook_url, json=payload)

实操中,你在daily_report.py末尾这样调用:

# 发送邮件(传统方式)
send_email(
    subject=f"[禅道日报] {today_str}",
    body=f"今日缺陷趋势:新增{new_cnt},关闭{close_cnt},进行中{active_cnt}。",
    to_emails=['test-leader@yourcompany.com', 'pm@yourcompany.com'],
    attachments=['daily_report.xlsx']
)

# 同时推送企业微信(推荐)
send_webhook(
    title="禅道日报已生成",
    message=f"📅 {today_str} | 🐞 新增{new_cnt} | ✅ 关闭{close_cnt} | ⏳ 进行中{active_cnt}",
    webhook_url=os.getenv('WECHAT_WEBHOOK', '')
)

实操心得:企业微信Webhook的markdown格式对换行和缩进极其敏感。我踩过的坑是:content字符串里用了\n\n,但企业微信要求必须是\n>开头的引用块,否则渲染失败。现在所有Webhook消息都严格遵循>开头的格式,确保100%正确显示。

4. 核心SQL脚本详解:从daily_report.sql到project_summary.sql的业务逻辑穿透

4.1 daily_report.sql:日报的“黄金三角”指标体系

日报不是数据堆砌,而是围绕“交付健康度”构建的三个核心问题:
- Q1:今天有多少新问题冒出来? → 新增缺陷数(active_bug_count)
- Q2:今天解决了多少老问题? → 关闭缺陷数(closed_bug_count)
- Q3:今天有多少事在推进中? → 进行中任务数(active_task_count)

daily_report.sql的完整逻辑如下(已简化注释):

-- daily_report_v2.sql
-- 【指标1】当日新增缺陷(按模块、优先级分布)
SELECT 
  m.name AS module_name,
  b.priority,
  COUNT(*) AS bug_count
FROM zt_bug b
LEFT JOIN zt_module m ON b.module = m.id
WHERE b.openedDate >= '{start_date}' AND b.openedDate < '{end_date}'
GROUP BY m.name, b.priority
ORDER BY m.name, b.priority;

-- 【指标2】当日关闭缺陷(按解决人、解决方式分布)
SELECT 
  u.realname AS resolved_by,
  b.resolution,
  COUNT(*) AS closed_count
FROM zt_bug b
LEFT JOIN zt_user u ON b.resolvedBy = u.account
WHERE b.closedDate >= '{start_date}' AND b.closedDate < '{end_date}'
GROUP BY u.realname, b.resolution
ORDER BY closed_count DESC;

-- 【指标3】当日进行中任务(按执行人、延期状态分布)
SELECT 
  u.realname AS assigned_to,
  CASE WHEN t.deadline < CURDATE() AND t.status NOT IN ('done','cancel') THEN 'delayed' ELSE 'on_time' END AS deadline_status,
  COUNT(*) AS task_count
FROM zt_task t
LEFT JOIN zt_user u ON t.assignedTo = u.account
WHERE t.status NOT IN ('done','cancel','pause') 
  AND t.openedDate <= '{end_date}'
GROUP BY u.realname, deadline_status;

这里的关键业务规则:
- “进行中任务”的判定:状态不能是done/cancel/pause,且openedDate必须≤截止日(排除未来才开启的任务);
- “延期任务”的判定:deadline < CURDATE()且状态非已完成/已取消,这比单纯看status='delayed'更准确,因为禅道里很多任务不会主动标记为延期;
- 模块名称关联:zt_module表可能有空模块(m.name IS NULL),SQL中用LEFT JOIN保留,后续Python脚本会将NULL模块归类为“未分配”。

4.2 bug_time_summary.sql:缺陷生命周期的“四段式”时长分析

缺陷分析不能只看总数,更要关注“流转效率”。我们定义缺陷生命周期为四个阶段:
1. 创建→解决(opened → resolved):开发介入速度;
2. 解决→关闭(resolved → closed):测试验证速度;
3. 创建→关闭(opened → closed):端到端修复速度;
4. 关闭→重新激活(closed → active):缺陷复发率。

bug_time_summary.sql用UNION ALL一次性拉取四段数据:

-- bug_time_summary_v1.sql
-- 阶段1:创建→解决(仅统计已解决缺陷)
SELECT 
  'opened_to_resolved' AS stage,
  AVG(TIMESTAMPDIFF(HOUR, b.openedDate, b.resolvedDate)) AS avg_hour,
  MIN(TIMESTAMPDIFF(HOUR, b.openedDate, b.resolvedDate)) AS min_hour,
  MAX(TIMESTAMPDIFF(HOUR, b.openedDate, b.resolvedDate)) AS max_hour,
  COUNT(*) AS count
FROM zt_bug b 
WHERE b.status = 'resolved' 
  AND b.openedDate >= '{start_date}' 
  AND b.openedDate < '{end_date}'

UNION ALL

-- 阶段2:解决→关闭(仅统计已关闭缺陷)
SELECT 
  'resolved_to_closed' AS stage,
  AVG(TIMESTAMPDIFF(HOUR, b.resolvedDate, b.closedDate)) AS avg_hour,
  MIN(TIMESTAMPDIFF(HOUR, b.resolvedDate, b.closedDate)) AS min_hour,
  MAX(TIMESTAMPDIFF(HOUR, b.resolvedDate, b.closedDate)) AS max_hour,
  COUNT(*) AS count
FROM zt_bug b 
WHERE b.status = 'closed' 
  AND b.resolvedDate IS NOT NULL 
  AND b.closedDate IS NOT NULL
  AND b.resolvedDate >= '{start_date}' 
  AND b.closedDate < '{end_date}'

UNION ALL

-- 阶段3:创建→关闭(端到端)
SELECT 
  'opened_to_closed' AS stage,
  AVG(TIMESTAMPDIFF(HOUR, b.openedDate, b.closedDate)) AS avg_hour,
  MIN(TIMESTAMPDIFF(HOUR, b.openedDate, b.closedDate)) AS min_hour,
  MAX(TIMESTAMPDIFF(HOUR, b.openedDate, b.closedDate)) AS max_hour,
  COUNT(*) AS count
FROM zt_bug b 
WHERE b.status = 'closed' 
  AND b.openedDate >= '{start_date}' 
  AND b.closedDate < '{end_date}'

UNION ALL

-- 阶段4:关闭→重新激活(复发缺陷)
SELECT 
  'closed_to_reactivated' AS stage,
  AVG(TIMESTAMPDIFF(HOUR, b1.closedDate, b2.openedDate)) AS avg_hour,
  COUNT(*) AS count
FROM zt_bug b1
INNER JOIN zt_bug b2 ON b1.id = b2.activatedBug AND b2.activatedBug IS NOT NULL
WHERE b1.status = 'closed' 
  AND b2.status = 'active'
  AND b1.closedDate >= '{start_date}' 
  AND b2.openedDate < '{end_date}';

这个SQL的价值在于:它把分散在不同时间点的操作,用关联查询串成一条完整的流水线。当你发现“创建→解决”平均要48小时,但“解决→关闭”只要2小时,问题就清晰了——瓶颈在开发环节,而非测试环节。这种归因分析,是手工Excel永远做不到的。

4.3 project_summary.sql:项目进度的“三维度”透视

项目进度报表常犯的错误是只看“整体进度%”,而忽略背后的水分。project_summary.sql从三个维度交叉验证:

维度查询逻辑业务意义
计划进度SELECT progress FROM zt_project WHERE id = ?禅道后台手动填写的进度,主观性强
任务完成率COUNT(task WHERE status='done') / COUNT(task)客观数据,反映真实交付量
工时饱和度SUM(task.estimate) / (COUNT(user)*8*days)团队资源是否过载或闲置

完整SQL:

-- project_summary_v1.sql
SELECT 
  p.name AS project_name,
  p.progress AS planned_progress,
  ROUND(
    (SELECT COUNT(*) FROM zt_task t WHERE t.project = p.id AND t.status = 'done') * 100.0 / 
    NULLIF((SELECT COUNT(*) FROM zt_task t WHERE t.project = p.id), 0), 2
  ) AS task_completion_rate,
  ROUND(
    (SELECT COALESCE(SUM(t.estimate), 0) FROM zt_task t WHERE t.project = p.id) * 100.0 / 
    NULLIF((SELECT COUNT(DISTINCT t.assignedTo) FROM zt_task t WHERE t.project = p.id AND t.assignedTo != '') * 8 * DATEDIFF(p.end, p.begin), 0), 2
  ) AS workload_saturation,
  p.begin AS start_date,
  p.end AS end_date,
  DATEDIFF(p.end, p.begin) AS total_days
FROM zt_project p
WHERE p.status IN ('doing', 'wait', 'suspended')
  AND p.deleted = '0'
ORDER BY p.progress DESC;

这里NULLIF()函数至关重要:当项目无任务(COUNT(*)=0)或无指派人(COUNT(DISTINCT)=0)时,避免除零错误,返回NULL,Python脚本会将其显示为N/A。这种防御性SQL写法,让报表在禅道数据异常时依然健壮。

5. 实操过程与自动化部署:从本地调试到定时任务的全流程

5.1 本地环境搭建:5分钟完成首次运行

部署不是“拷贝代码+改配置”那么简单,而是要建立一套可验证的本地沙箱。以下是标准流程:

  1. 安装依赖(建议使用虚拟环境):
    bash python -m venv zentao_env source zentao_env/bin/activate # Linux/Mac # zentao_env\Scripts\activate # Windows pip install pymysql openpyxl pandas requests

  2. 准备禅道数据库快照(关键!):
    - 不要直接连生产库!从禅道备份中恢复一个最近的zentao.sql到本地MySQL(5.7+);
    - 或使用mysqldump导出测试环境库:mysqldump -h 192.168.1.100 -u reader -p zentao > zentao_test.sql;
    - 导入本地:mysql -u root -p zentao_test < zentao_test.sql。

  3. 配置数据库连接:
    - 编辑common_mysql_config.py,设置DB_HOST='127.0.0.1', DB_NAME='zentao_test';
    - 或更推荐:创建config/local_db.conf,内容为:
    DB_HOST=127.0.0.1 DB_PORT=3306 DB_USER=root DB_PASSWORD='your_local_root_pass' DB_NAME=zentao_test

  4. 首次运行日报脚本:
    bash python daily_report.py --date 2024-06-01 # 输出:daily_report_20240601.xlsx 已生成 # 打开Excel,检查Summary Sheet的数字是否与禅道网页端一致

实操心得:首次运行务必用--date参数指定一个历史日期(如昨天),而不是默认用today。因为禅道测试库的数据可能没有今天的记录,直接跑daily_report.py会报“无数据”,让你误以为脚本失败。用历史日期,能快速验证SQL逻辑和Python流程是否通畅。

5.2 自动化调度:Linux定时任务与Windows任务计划程序

自动化不是终点,而是起点。日报必须“无人值守”,否则就失去了意义。

Linux服务器(推荐):

# 编辑crontab
crontab -e

# 每天早上8:30执行日报(生成昨日数据)
30 8 * * * cd /opt/zentao-report && /opt/zentao-env/bin/python daily_report.py >> /var/log/zentao-daily.log 2>&1

# 每周一早上9:00执行周报(生成上周一至周日数据)
0 9 * * 1 cd /opt/zentao-report && /opt/zentao-env/bin/python weekly_report.py >> /var/log/zentao-weekly.log 2>&1

Windows服务器(兼容方案):
- 使用“任务计划程序”,创建基本任务;
- 触发器:每日/每周;
- 操作:启动程序 → C:\Python39\python.exe,参数:C:\zentao-report\daily_report.py;
- “使用最高权限运行”必须勾选,否则可能因权限不足无法写入Excel文件。

注意:Linux下cd /path && python script.py是原子操作,确保在正确目录执行;Windows下需在“起始于”字段填入脚本所在目录路径,否则read_excel.py会找不到相对路径的模板文件。

5.3 邮件与Webhook配置:让报告真正触达决策者

邮件配置最容易出错的是SMTP认证。禅道常用的企业邮箱(如腾讯企业邮、阿里云邮箱)要求:
- SMTP服务器:smtp.exmail.qq.com(腾讯)或smtp.mxhichina.com(阿里);
- 端口:587(TLS)或465(SSL);
- 用户名:必须是完整邮箱地址(qa-report@yourcompany.com),而非用户名;
- 密码:必须是“客户端专用密码”,而非邮箱登录密码(在邮箱管理后台开启SMTP服务并生成)。

Webhook配置更简单,但要注意:
- 企业微信机器人需在群聊中添加,并复制Webhook URL(形如https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx);
- 钉钉机器人需在群设置中添加,并获取Webhook(形如https://oapi.dingtalk.com/robot/send?access_token=xxx);
- 将URL存入环境变量:export WECHAT_WEBHOOK="https://qyapi.weixin.qq.com/...",脚本自动读取。

5.4 常见问题与排查技巧实录

Q1:脚本报错 pymysql.err.OperationalError: (1045, "Access denied")
  • 原因:数据库密码含特殊字符(如@, /, :)未转义;
  • 排查:在common_mysql_config.py中临时打印DB_URL,检查是否被截断;
  • 解决:确认DB_PASSWORD已用quote_plus()处理,或改用环境变量注入。
Q2:Excel导出后,中文显示为乱码()
  • 原因:pandas.to_excel()默认编码与系统不匹配;
  • 排查:检查read_excel.py中是否使用了engine='openpyxl'(必须);
  • 解决:确保安装openpyxl(pip install openpyxl),而非xlsxwriter。
Q3:日报中“高优缺陷占比”为0,但禅道网页能看到高优缺陷
  • 原因:SQL中b.priority IN (1,2)条件错误,禅道8.x中priority字段是字符串('1', '2'),非数字;
  • 排查:在Navicat中执行SELECT DISTINCT priority FROM zt_bug LIMIT 5,确认数据类型;
  • 解决:将SQL改为b.priority IN ('1','2')。
Q4:weekly_report.py生成的周报,日期范围总是错一天
  • 原因:脚本中start_date = (today - timedelta(days=7)).strftime('%Y-%m-%d'),但禅道的“本周”通常指周一至周日,而timedelta(days=7)是自然日;
  • 排查:打印start_date和end_date变量值;
  • 解决:改用calendar模块计算周一:
    python import calendar def get_last_monday(): today = datetime.date.today() last_monday = today - datetime.timedelta(days=today.weekday()) return last_monday.strftime('%Y-%m-%d')
Q5:企业微信消息不显示,或显示为空白
  • 原因:markdown内容中>后缺少空格,或换行符格式错误(Windows用\r\n,企业微信只认\n);
  • 排查:用print(repr(message))检查字符串实际内容;
  • 解决:统一用\n,且确保每行以>开头(注意空格)。

最后分享一个小技巧:在所有脚本顶部添加#!/usr/bin/env python3,并赋予执行权限chmod +x daily_report.py,即可直接./daily_report.py运行,省去python命令前缀,这对运维同学更友好。

6. 质量保障与持续演进:如何让这套工具活过三年

工具的生命力不在于首发有多炫,而在于能否随业务一起成长。过去三年,这套工具经历了三次重大迭代,每一次都源于一个真实的复盘会议:

  • 第一次迭代(禅道8.0升级):禅道从7.x升级到8.0,zt_bug表新增storyVersion字段,zt_project表progress字段从整数变为小数。我们没有重写SQL,而是在common_read_sql.py中增加了schema_version_check()函数,自动检测表结构,对progress字段做ROUND(progress, 2)处理,确保报表数字不变。

  • 第二次迭代(引入自动化覆盖率):测试经理提出“要统计每个模块的自动化用例覆盖率”。我们没有大改框架,而是新增了module_automation_report.py和module_automation.sql,后者关联zt_case(用例表)和zt_module,用COUNT(CASE WHEN c.type='auto' THEN 1 END)/COUNT(*)计算覆盖率。整个新增过程不到1小时。

  • 第三次迭代(支持多环境):公司有了测试、预发、生产三套禅道环境。我们在common_mysql_config.py中增加了ENVIRONMENT环境变量,默认prod,可设为test或staging,自动加载对应数据库配置,daily_report.py无需任何修改。

这种演进能力,源于两个设计哲学:
1. SQL即契约:所有业务规则沉淀在SQL文件中,版本化管理,变更可追溯;
2. Python即胶水:Python脚本只做数据搬运和格式转换,不掺杂业务逻辑,替换成本趋近于零。

所以,如果你今天开始部署这套工具,我的建议是:
- 第一天:跑通daily_report.py,确保本地能生成正确Excel;
- 第一周:接入企业微信Webhook,让日报消息触达团队;
- 第一个月:根据团队复盘会反馈,新增1-2个定制SQL(如online_bug.sql统计线上问题);
- 第一年:将common_deal_table.py中的通用函数(如趋势图生成)封装为独立包,供其他团队复用。

它不会一夜之间改变你的工作方式,但当你某天早上打开邮箱,看到那份自动生成的日报,上面清晰地标着“高优缺陷占比35%(↑12%),主要集中在支付模块”,而你只需花3分钟确认原因、@相关开发,然后继续推进今天的测试用例——那一刻,你会明白,真正的效率提升,从来不是更快地点击鼠标,而是让数据自己开口说话。

我个人在实际使用中发现,最有效的推广方式不是培训文档,而是带着测试工程师一起跑一次bug_time_detail.py,把生成的明细表导入禅道缺陷列表页,让他们亲眼看到:原来那个拖了5天没解决的缺陷,其实在第2天就已被开发标记为“已解决”,只是测试没及时验证关闭。这种“所见即所得”的冲击力,远胜千言万语。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:直接对接禅道MySQL数据库,用Python脚本批量跑出测试团队日常需要的各类数据报表。每天早上自动出一份日报,每周一生成周报,内容包括缺陷新增/关闭趋势、各模块缺陷分布、缺陷平均修复时长、线上问题与日常缺陷对比、项目整体进度、任务完成率、成员工作量分布等。所有分析都基于真实数据库表结构,配套SQL文件已预置好常用查询逻辑(如daily_report.sql、bug_time_summary.sql、project_detail.sql等),Python脚本支持一键执行、Excel导出(read_excel.py)、邮件自动发送(common_mail_test.py)和通用表格处理(common_deal_table.py)。脚本模块化设计,daily_report.py、weekly_report.py、bug_time_detail.py、project_summary.py等可单独运行,也可组合调用;数据库连接配置统一放在common_mysql_config.py里,改一次密码全链路生效。适配禅道8.x及以上版本,部署前只需填入MySQL地址、账号、密码和禅道数据库名,无需额外安装服务或依赖复杂中间件。适合测试负责人、质量保障工程师、研发项目经理做日常数据盯盘、迭代复盘和质量度量。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

2026物流数据分析学习路线:从Excel到SQL实战指南 在产业数字化浪潮下,物流行业正从劳动密集型向数据密集型转型,数据分析已成为连接业务决策与技术执行的枢纽型技能。其核心原理,是通过对仓储、运输、配送、客服等环节产生的海量记录进行清洗、透视与建模,将零散的业务现象转化为可量化、可追踪、可验证的管理指标。掌握这一能力不仅需要理解指标口径、数据地图等业务框架,更需要依次熟练运用Excel、SQL、Python及BI工具,形成从取数、清洗、分析到可视化呈现的完整链路。无论是评估区域时效、定位异常环节,还是优化车队排班,这套方法都能帮助企业降低运营成本、提升服务质量。 阅读详情

相关推荐

软件测试实习四周指南:环境搭建、用例设计、缺陷管理与回归测试

软件测试的核心,是把需求与风险转化为可执行、可验证的质量活动。其原理并不复杂:先搭建稳定的测试环境,再通过等价类、边界值等方法设计用例,执行后以标准化缺陷单跟踪问题,最后用回归测试确认修复且不引入新风险。技术价值在于提升缺陷复现率、缩短沟通链路,并让测试进度与质量趋势可度量。在电力管理系统、C/S与B/S混合架构等企业级场景中,环境版本、端口映射、参数文件、测试管理工具(如QC、禅道、Jira)都会直接影响结果可信度。围绕一份软件测试毕业实习报告,四周节奏被拆成环境搭建、用例设计、缺陷管理与回归测试的可复用

weixin_33922672的博客 384

研发部工作日志使用教程

研发部工作日志app使用教程一 下载地址二 添加日报四 添加周报五 禅道绑定六 日报审批七 日报批量审批八 周报审批九 日报与周报审阅 您好!这是研发部工作日志app的使用教程。 研发部工作日志app用于研发部部门内部。用户权限分为组员、组长、产品经理和部长。 组员可以填写日志、周报,绑定禅道账号,并将日报提交到禅道内。 组长具有组员的所有功能,还可以审批组内的日志和周报。 产品经理可以填写日志和周报,填写完后自动变为已审批状态。 部长可以审阅部门内所有已审批的日志和周报。 一 下载地址 安卓app下载地址

u011343730的博客 4077

嵌入式充电协议深度解析:从QC到PD3.1的技术演进与实战应用

本文深入解析了从QC到PD3.1的嵌入式充电协议技术演进与实战应用。通过电压谈判、协议芯片设计、Type-C接口优化等关键技术,详细介绍了快充协议在嵌入式系统中的实现挑战与解决方案,包括兼容性测试、EMC问题处理及空间限制创新设计,为开发者提供了宝贵的实践经验。

weixin_29194817的博客 419

zentao_reporter一款开源版禅道报告生成工具,便捷生成一段时间内禅道用户bug、任务相关报告,方便项目跟踪和管理,直观的统计每个员工的工作

zentao_reporter 一款开源版禅道报告生成工具,便捷生成一段时间内禅道用户bug、任务相关报告。 项目地址 欢迎star和fork https://github.com/zcyuefan/zentao_reporter 已实现功能 BUG创建、激活、关闭、解决、当前待处理BUG情况汇总 BUG创建详细 BUG激活详细 BUG关闭详细 BUG解决详细 当前待处理BUG详细 ...

zcyuefan的博客 3894

RK3588上跑通Zipformer语音识别的3个坑与填坑实录(附完整编译命令)

本文详细记录了在RK3588开发板上部署Zipformer语音识别模型时遇到的三个典型问题及其解决方案,包括静态库版本冲突、编译脚本配置错误以及模型转换精度调优。文章提供了完整的编译命令和实战步骤,帮助开发者快速在边缘设备上实现高效的语音识别应用。

l6m7n8的博客 711

基于PINN的一个简单的求解偏微分方程实例

本人是做化工模拟的一名学生,最近在学习PINN(Physics-Informed Neural Networks,物理信息神经网络)对管道动力学进行建模研究,PINN由于其对机理与数据的良好兼顾性非常热门,本文是作者对PINN入门研究过程的一个练手小题目,main code也是作者代码是基于pytorch2.6.0写的,发上来供各位参考,欢迎研究管道动力学和PINN的小伙伴一起讨论~

weixin_64491760的博客 1739

【测试能力提升】Jira 和禅道数据库分析,方便你写周报、写总结、出报告

方便你写周报、写总结、出报告

公众号已改名为-程序员阿沐 2160

西门子1500T系列凸轮同步(CAMIN指令用法)

添加凸轮工艺对象(TO_CAM),也就是凸轮表。开始编程,先写2个轴的使能、回原点与主轴的定位。监控主轴与从轴的位置、速度关系是否满足实验要求。1.添加工艺对象(1个定位轴,1个同步轴)调用CAMIN指令 ,凸轮耦合。主轴为旋转轴且为模数轴。3.调用插补凸轮盘指令。4.仿真、监控、调试。

gyxgyx789的博客 1万+

如何高效跟进项目进度?试试禅道几个功能

项目管理中,正确的跟进方法不仅能保证项目按时按质完成,还能帮助团队识别和解决过程中出现的问题,从而避免资源的浪费并提升整体工作效率。

weixin_45228755的博客 3083

STC32G电调调试血泪史:从TPH1R403NL MOS管烧毁到PWM信号异常排查全记录

本文详细记录了STC32G无刷电调调试过程中的常见问题与解决方案,包括MOS管烧毁、PWM信号异常等关键故障排查。通过电源系统检测、驱动电路验证及三相平衡调试等实战经验,帮助硬件爱好者快速定位问题,提升电调调试效率。特别针对TPH1R403NL等MOS管的保护措施进行了重点分析。

weixin_33736048的博客 550

【微服务】Spring AI Alibaba Jmus 从部署到项目实战详解

Spring AI Alibaba Jmus 从部署到项目实战详解

congge 4183

周报 8月2日

周报 支浩宇 8.2 1. 本周工作 计划完成度:50% (1) 流量转化的功能本周完成度0%。现在没人跟这个事情,测试环境到现在都没有。没有任何进展。 在这种情况下,一定不能慌。其实有组织有效率的话,一天之内可以完成测试,所以不用急,等相关部门来跟进就可以了。 星期三有个名叫王.龙的人,刚刚入职,连CC账号都没有,完全是个菜鸟。他来找我,说他负责“流量统计”。我跟他谈了一会,...

pagen_hd的专栏 221

100 道大数据开发技术原理与实战面试宝典(必过答案详细解析)I

在数字化浪潮席卷全球的今天,大数据开发工程师已成为企业数字化转型的核心力量。无论是互联网巨头的用户行为分析,还是金融机构的风险控制,亦或是智慧城市的数据中枢,都离不开大数据技术的支撑。然而,面对BAT等头部企业严格的面试要求,候选人不仅需要掌握扎实的理论基础,更需具备将技术落地的实战能力。本文基于历年高频面试题与企业真实场景需求,梳理100道必考题目,涵盖基础概念、框架原理、算法设计、性能优化等核心领域,助你构建完整的知识体系,从容应对面试挑战。

AI天才研究院 1384

程序员如何写出高质量工作日报/周报?

本文是关于程序员如何撰写高质量工作日报和工作周报的指南,涵盖了日报和周报的核心价值、写作方法论、三维框架、避坑指南、工具链推荐。

半青年的博客 2601

推荐系统(十六):基于ESMM的商品召回/推荐系统

ESMM(Entire Space Multi-Task Model)是阿里巴巴提出的多任务学习框架,通过联合建模点击率(CTR)和点击转化率(CVR)解决传统CVR模型样本稀疏问题。其核心思想是将 CVR 定义为 CTR 与 CTCVR 的条件概率,模型包含两个子任务。

Jin_Kwok的博客 1264

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

影刀RPA实战:日报周报月报自动生成系统

本文介绍了一套基于影刀RPA的自动化报表生成系统,可大幅提升职场工作效率。该系统能够从Google Analytics、CRM、客服系统等多源自动采集数据,整合分析后生成结构化的日报、周报和月报,并通过邮件自动发送。文章详细展示了系统架构设计、报表模板结构以及具体实现步骤,预计每年可节省约244小时(30个工作日)的手工操作时间。读者可获得完整的实战方案,包括3套可直接使用的报表模板和自动化流程代码,实现真正的"一键生成"报表功能。

代码仓是开发的项目 392

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

聪明的项目经理,都会利用周报让老板重视你!

在职场中,写日报、周报是工作标配。但是,这也是让很多人感到头疼且抗拒的事情。尤其是项目经理们,明明每天都已经忙得脚不沾地了,哪有时间去写那个啥报?环环总结了几条大家讨厌写周报的原因,看看...

JAVA葵花宝典 319

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

工作日报模板_天天写日报,到底有什么用途

关注并将「人人都是产品经理」设为星标每天早 07 : 45 按时送达要问数据分析师最讨厌的一件事是什么,很多人会回答是“日、周、月、季、年报制度”,这已经变成了天天都得干,干了还没啥用的鸡肋。为什么要搞这样一个制度呢?它的意义在哪里?本文作者将对此进行六个维度的分析,希望对你有帮助。全文共2953字,阅读需要 6分钟—————— BEGIN ——————日、周、月、季、年报制度,可...

weixin_39643865的博客 1485

一劳永逸的日报月报制作方法,还不快来get

亿信ABI提供了丰富的数据库类型接入,包括主流的关系型数据库以及分布式数据库,能将政府、企业使用的业务系统数据对接到平台中,提供后续建模分析使用,数据库类型包括:Mysql、Oracle、SQL Server、DB2、GBase、PetaBase、Essbase等,同时也支持通过接入其他数据库驱动的方式自定义数据库。在报表制作完成后,只需要通过报表的订阅功能,就可以将做好的报表定时发布出去,从不厌其烦的重复发布操作中解脱,方便快捷地设置日报、月报、季报、年报等任务,不需要额外的工作。转存失败重新上传取消。

esensoft123的博客 744

程序员的我们天天写日、周、月、年报,到底有什么用途?又不看!!!

让我们一起吐槽和分析写在开头日报制度的深层意义日报的作用周报的作用月报/季报的作用年报本该这么用 写在开头 日、周、月、季、年报制度,可能是数据分析领域最大的一个“咕咚来了”:每一个新人在进公司的时候,都会得到一个类似传家宝一样的日、周、月报模板,交接工作的前辈会告诉你:“对着模板更新它们,然后指定发给某某某几个人”。 至于: 为啥要发 为啥做成这样 发了人家看不看 从来没人解释过,新人往往也懒得问——毕竟在各种朋友圈文章里,模型才是终极归宿,报表算啥玩意? 于是这些常规报表变成了天天都得干,干了还没啥用的

点滴聚变 2933

sql取近四周数据_它是最给力的数据分析体系,却被90%的新人忽略!

日、周、月、季、年报制度,可能是数据分析领域最大的一个“咕咚来了”。每一个新人在进公司的时候,都会得到一个类似传家宝一样的日、周、月报模板,交接工作的前辈会告诉你:“对着模板更新它们,然后指定发给某某某几个人”。至于:l为啥要发l为啥做成这样l发了人家看不看从来没人解释过新人往往也懒得问。毕竟在各种朋友圈文章里,模型才是终极归宿,报表算啥玩意。于是这些常规报表变成了天天都得干,干了...

weixin_39604280的博客 249

从繁琐到自动:报表自动化实践分享

如何通过 EasySQLMAIL 工具实现内部报表的全自动推送,从而摆脱了每天重复运行 SQL、导出报表、发送邮件的繁琐流程。

pb90001的博客 1680

《数字化项目管理革命:用工具重构效率的六大实战策略》

记住:选择工具时要像选手术刀般精准,使用时需如匠人般专注,迭代时应保持探险家般的好奇。2023年PMI报告显示,使用专业工具的项目团队交付准时率提升47%,需求变更率下降32%。工欲善其事必先利其器,现代项目管理工具已从简单的任务记录进化为智能决策中枢,形成覆盖全生命周期的数字神经网络。→ [立即下载] https://sourceforge.net/projects/dblens-for-mysql。AI对象生成:自动创建表/视图/存储过程/函数。数据字典中心:自动生成文档,支持PDF。

linjinpeng0819的博客 1488

互联网数据分析的主要工作内容是什么?

弄完这些七七八八的,答主就开始整理一下今晚周会的数据需求,把数拉出来,哪些异常的数据要看一下,简单分析一下原因,毕竟老板看了日报没有大惊嘛。没过一会财务总监就来找答主提个数了,财务总监第一次来找答主,不知道 xx 数在哪里取,其实答主也不知道,答主只管业务这边的,但是有数据权限。Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。,运行一下以前写好的 python 自动脚本,生成一下日报,然后打水去。

xiangxueerfei的博客 121

蚂蚁金服上市后取消了周报,为什么我说不合理?

点击蓝色“有关SQL”关注我哟加个“星标”,天天与10000人一起快乐成长听说蚂蚁金服上市后,不用再写周报了。全公司上下奔走相告,每个人好像比财务自由还开心。听到这个消息,我低头思忖,蚂...

wujiandao的专栏 848

sql取近四周数据_它是最给力的数据分析体系,却被90%的新人忽略

公众号:接地气学堂作者:接地气的陈老师日、周、月、季、年报制度,可能是数据分析领域最大的一个“咕咚来了”。每一个新人在进公司的时候,都会得到一个类似传家宝一样的日、周、月报模板,交接工作的前辈会告诉你:“对着模板更新它们,然后指定发给某某某几个人”。至于:l 为啥要发l 为啥做成这样l 发了人家看不看从来没人解释过新人往往也懒得问。毕竟在各种朋友圈文章里,模型才是终极归宿,报表算啥玩意。于是这些常...

weixin_39610956的博客 140
上一篇: 基于STC89C52的mm-ss数码管倒计时器:矩阵键盘设定+蜂鸣提醒
下一篇: 高通多代骁龙芯片媒体HAL源码包(8084至8996全系列)
pluto
博客等级 码龄25年 46粉丝 1562原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值