Files
web-Iot/.workbuddy/gen_monthly_report.py
2026-09-22 19:37:13 +08:00

653 lines
30 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
Generate August 2026 Monthly Report Word Document for 葛昀.
Audience: 老板 - 通俗易懂、图文并茂
"""
import os
from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor, Emu
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
# ---- config ----
SCREENSHOT_DIR = r"D:\code\机器人智慧服务系统\.workbuddy\screenshots"
OUTPUT_PATH = r"D:\code\机器人智慧服务系统\2026年8月工作月度报告-葛昀.docx"
NAME = "葛昀"
MONTH = "2026年8月"
DEPT = "智慧运维研发组"
PERIOD = "2026.08.01 — 2026.08.31"
# ---- helpers ----
def set_cell_shading(cell, color):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
shading = OxmlElement('w:shd')
shading.set(qn('w:fill'), color)
shading.set(qn('w:val'), 'clear')
tcPr.append(shading)
def set_cell_border(cell, color="BFBFBF", sz=4):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
tcBorders = OxmlElement('w:tcBorders')
for border_name in ('top', 'left', 'bottom', 'right'):
border_el = OxmlElement(f'w:{border_name}')
border_el.set(qn('w:val'), 'single')
border_el.set(qn('w:sz'), str(sz))
border_el.set(qn('w:color'), color)
tcBorders.append(border_el)
tcPr.append(tcBorders)
def add_page_break(doc):
p = doc.add_paragraph()
run = p.add_run()
run.add_break(WD_BREAK.PAGE)
def add_p(doc, text, size=10.5, bold=False, color=None, align=None, indent_first=False, space_after=4):
p = doc.add_paragraph()
if align == "center":
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
elif align == "right":
p.alignment = WD_ALIGN_PARAGRAPH.RIGHT
elif align == "justify":
p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
else:
p.alignment = WD_ALIGN_PARAGRAPH.LEFT
if indent_first:
p.paragraph_format.first_line_indent = Pt(21) # 2字符
run = p.add_run(text)
run.font.size = Pt(size)
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
run.font.bold = bold
if color:
run.font.color.rgb = RGBColor(*color)
p.paragraph_format.space_after = Pt(space_after)
return p
def add_h1(doc, text):
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.LEFT
run = p.add_run(text)
run.font.size = Pt(18)
run.font.bold = True
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
run.font.color.rgb = RGBColor(31, 73, 125)
p.paragraph_format.space_before = Pt(14)
p.paragraph_format.space_after = Pt(8)
# 下划线效果:加一条浅色横线
pPr = p._element.get_or_add_pPr()
pBdr = OxmlElement('w:pBdr')
bottom = OxmlElement('w:bottom')
bottom.set(qn('w:val'), 'single')
bottom.set(qn('w:sz'), '12')
bottom.set(qn('w:color'), '1F497D')
bottom.set(qn('w:space'), '4')
pBdr.append(bottom)
pPr.append(pBdr)
return p
def add_h2(doc, text):
p = doc.add_paragraph()
run = p.add_run(text)
run.font.size = Pt(14)
run.font.bold = True
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
run.font.color.rgb = RGBColor(46, 116, 181)
p.paragraph_format.space_before = Pt(10)
p.paragraph_format.space_after = Pt(4)
return p
def add_h3(doc, text):
p = doc.add_paragraph()
run = p.add_run(text)
run.font.size = Pt(12)
run.font.bold = True
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
run.font.color.rgb = RGBColor(31, 73, 125)
p.paragraph_format.space_before = Pt(6)
p.paragraph_format.space_after = Pt(2)
return p
def add_bullet(doc, text, size=10.5):
p = doc.add_paragraph(style='List Bullet')
run = p.add_run(text)
run.font.size = Pt(size)
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
p.paragraph_format.space_after = Pt(2)
return p
def add_numbered(doc, text, size=10.5):
p = doc.add_paragraph(style='List Number')
run = p.add_run(text)
run.font.size = Pt(size)
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
p.paragraph_format.space_after = Pt(2)
return p
def add_image(doc, name, max_width_inches=5.5, caption=None):
"""Insert a PNG screenshot with optional caption."""
fp = os.path.join(SCREENSHOT_DIR, name)
if not os.path.exists(fp):
add_p(doc, f"[图片缺失: {name}]", size=9, color=(150, 150, 150))
return None
p = doc.add_paragraph()
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run()
run.add_picture(fp, width=Inches(max_width_inches))
p.paragraph_format.space_before = Pt(6)
p.paragraph_format.space_after = Pt(2)
if caption:
cp = doc.add_paragraph()
cp.alignment = WD_ALIGN_PARAGRAPH.CENTER
cr = cp.add_run(f"图 {caption}")
cr.font.size = Pt(9)
cr.font.italic = True
cr.font.name = 'Microsoft YaHei'
cr._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
cr.font.color.rgb = RGBColor(89, 89, 89)
cp.paragraph_format.space_after = Pt(10)
return p
def add_kv_table(doc, rows, col_widths=(1.5, 5.0)):
"""Add a simple two-column key-value table."""
table = doc.add_table(rows=len(rows), cols=2)
table.alignment = WD_TABLE_ALIGNMENT.CENTER
table.autofit = False
for i, (k, v) in enumerate(rows):
for j, val in enumerate((k, v)):
cell = table.cell(i, j)
cell.width = Inches(col_widths[j])
cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
set_cell_border(cell, "BFBFBF")
if j == 0:
set_cell_shading(cell, "EAF1FA")
cell.text = ""
p = cell.paragraphs[0]
run = p.add_run(val)
run.font.size = Pt(10.5)
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
if j == 0:
run.font.bold = True
return table
def add_data_table(doc, headers, rows, widths=None, header_color="1F497D"):
n = len(rows) + 1
cols = len(headers)
table = doc.add_table(rows=n, cols=cols)
table.alignment = WD_TABLE_ALIGNMENT.CENTER
table.autofit = False
if widths:
for j, w in enumerate(widths):
for i in range(n):
table.cell(i, j).width = Inches(w)
# header
for j, h in enumerate(headers):
cell = table.cell(0, j)
cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
set_cell_border(cell, "BFBFBF")
set_cell_shading(cell, header_color)
cell.text = ""
p = cell.paragraphs[0]
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run(h)
run.font.size = Pt(10.5)
run.font.bold = True
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
run.font.color.rgb = RGBColor(255, 255, 255)
# rows
for i, row in enumerate(rows, start=1):
for j, v in enumerate(row):
cell = table.cell(i, j)
cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
set_cell_border(cell, "BFBFBF")
if i % 2 == 0:
set_cell_shading(cell, "F2F6FB")
cell.text = ""
p = cell.paragraphs[0]
p.alignment = WD_ALIGN_PARAGRAPH.LEFT if j > 0 else WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run(v)
run.font.size = Pt(10)
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
return table
# ---- 文档主体 ----
doc = Document()
# 默认样式
style = doc.styles['Normal']
style.font.name = 'Microsoft YaHei'
style.element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
style.font.size = Pt(10.5)
# 页边距
for section in doc.sections:
section.top_margin = Cm(2.2)
section.bottom_margin = Cm(2.2)
section.left_margin = Cm(2.2)
section.right_margin = Cm(2.2)
# ============================================================
# 封面
# ============================================================
cover_p = doc.add_paragraph()
cover_p.alignment = WD_ALIGN_PARAGRAPH.CENTER
cover_p.paragraph_format.space_before = Pt(120)
cr = cover_p.add_run("月度工作报告")
cr.font.size = Pt(36)
cr.font.bold = True
cr.font.name = 'Microsoft YaHei'
cr._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
cr.font.color.rgb = RGBColor(31, 73, 125)
cover_p2 = doc.add_paragraph()
cover_p2.alignment = WD_ALIGN_PARAGRAPH.CENTER
cr2 = cover_p2.add_run(MONTH)
cr2.font.size = Pt(28)
cr2.font.bold = True
cr2.font.name = 'Microsoft YaHei'
cr2._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
cr2.font.color.rgb = RGBColor(89, 89, 89)
# 间隔
for _ in range(2):
doc.add_paragraph()
# 封面信息表
cover_table = doc.add_table(rows=4, cols=2)
cover_table.alignment = WD_TABLE_ALIGNMENT.CENTER
cover_table.autofit = False
info = [
("报 告 人", f"{NAME}({DEPT})"),
("报告周期", PERIOD),
("汇报对象", "部门负责人"),
("报告日期", "2026 年 9 月"),
]
for i, (k, v) in enumerate(info):
for jj, val in enumerate((k, v)):
cell = cover_table.cell(i, jj)
cell.width = Inches(1.4 if jj == 0 else 2.4)
cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
set_cell_border(cell, "1F497D", sz=8)
if jj == 0:
set_cell_shading(cell, "1F497D")
cell.text = ""
p = cell.paragraphs[0]
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
run = p.add_run(val)
run.font.size = Pt(13)
run.font.bold = (jj == 0)
run.font.name = 'Microsoft YaHei'
run._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
if jj == 0:
run.font.color.rgb = RGBColor(255, 255, 255)
# 底部
for _ in range(6):
doc.add_paragraph()
foot = doc.add_paragraph()
foot.alignment = WD_ALIGN_PARAGRAPH.CENTER
fr = foot.add_run("机器人智慧服务系统 · 葛昀")
fr.font.size = Pt(11)
fr.font.name = 'Microsoft YaHei'
fr._element.rPr.rFonts.set(qn('w:eastAsia'), 'Microsoft YaHei')
fr.font.color.rgb = RGBColor(120, 120, 120)
add_page_break(doc)
# ============================================================
# 一、本月工作总览
# ============================================================
add_h1(doc, "一、本月工作总览")
add_p(doc,
f"本月({PERIOD}),本人主要围绕「光伏机器人智慧运维系统」的稳定性提升、功能迭代、跨端联调 "
f"与文档沉淀四条主线开展工作,累计完成代码提交 58 次,涵盖设备控制权限重构、WebSocket 通信优化、"
f"视频与日志管理模块建设、iOS/Android 双端协同、AI 大模型版本升级、软件著作权申报等多项重点工作。",
indent_first=True, align="justify")
add_h2(doc, "1.1 本月核心数据")
data_rows = [
("代码提交", "58 次", "git 提交,覆盖 8 个主要迭代方向"),
("工作主线", "4 条", "稳定性 / 功能迭代 / 跨端联调 / 文档沉淀"),
("周报输出", "5 篇", "覆盖 8 月完整工作节奏"),
("关键里程碑", "6 项", "WS 重构、视频模型升权、二级路由权开等"),
("跨团队联调", "1 项", "苏州算法团队路径规划全流程联调"),
("联调演示", "2 次", "现场联调保障、展会演示支持"),
("文档输出", "3 份", "用户手册、软著采集表、SOP 操作文档"),
]
add_data_table(doc, ["指标", "数值", "说明"], data_rows, widths=(1.4, 1.4, 3.6))
doc.add_paragraph()
add_h2(doc, "1.2 本月整体工作亮点")
highlights = [
"【控制权限】重构设备控制权限体系,由「单用户单设备」升级为「单设备单 Token」,彻底避免权限混乱、残留占用问题;"
"并完成 Web/APP 跨端抢占与释放的全场景闭环测试。",
"【联调突破】与苏州算法团队完成路径规划全流程联调——打点 → 数据保存 → 规划指令下发 → 算法回执 → "
"地图可视化展示规划路径与实时轨迹,业务链路完整跑通。",
"【架构升级】完成系统路由从一级到二级架构改造,页面跳转更清晰;同时将视频下载从 Node 脚本重构为 Java 接口,"
"统一后端技术栈,提升服务稳定性与可维护性。",
"【国际化】完成平台核心业务界面中英文双语切换,覆盖日常高频使用页面;为多语言场景落地提供基础。",
"【文档产出】独立输出 13 章 ~15 页的用户操作手册(含 16 张页面截图)、软著采集表(20 个字段全覆盖)、"
"以及标准 SOP 操作文档,便于后续交接与维护。",
]
for h in highlights:
add_bullet(doc, h)
add_page_break(doc)
# ============================================================
# 二、各周工作详情
# ============================================================
add_h1(doc, "二、各周工作详情")
# ---------- 第 1 周 ----------
add_h2(doc, "第 1 周(8/1 – 8/7):控制权限重构 + WS 通信优化")
add_h3(doc, "工作主题")
add_p(doc, "智慧运维系统平台底层通信机制优化、设备控制权限架构升级、跨团队算法联调启动。", indent_first=True)
add_h3(doc, "具体工作")
items = [
"优化 WebSocket 连接机制:实现单页面仅维持一次 WS 连接,路由切换自动销毁,避免多页面重复连接、"
"消息错乱与后台心跳堆积。",
"重构设备控制权限体系:从「单用户单设备控制」升级为「单设备单 Token 唯一占用」机制,"
"保证同一时间一台设备仅被一个有效连接控制。",
"新增主动释放权限功能,并完成闭环测试:Web 不同账号切换、Web 同账号页面切换、"
"Web 与 APP 跨端权限交替抢占与释放。",
"与苏州算法团队深度联调路径规划功能:完成设备打点、路径数据保存、规划指令下发、算法回执接收等"
"完整交互流程;地图可视化绘制规划轨迹与实时行走路径。",
"全程指导 APP 端完成路径规划全套业务流程适配与调试,配合团队完成苏州现场机器演示调试与保障。",
]
for i, it in enumerate(items, 1):
add_numbered(doc, it)
add_h3(doc, "本周产出")
add_image(doc, "00_login.png", 4.5, "系统登录界面 — 8 月初持续优化登录态")
# ---------- 第 2 周 ----------
add_h2(doc, "第 2 周(8/8 – 8/14):联调推进 + 组件迭代 + 文档沉淀")
add_h3(doc, "工作主题")
add_p(doc, "持续推进路径规划联调、平台基础功能完善、性能优化组件迭代,并沉淀 SOP 操作文档。", indent_first=True)
add_h3(doc, "具体工作")
items = [
"苏州路径规划联调持续推进,本周完成设备状态界面打点功能调试:机器在线状态、经纬度数据正常上报,"
"实时轨迹打点运行正常。",
"控制权限逻辑重构优化:基于新权限架构重构平台控制代码,彻底移除老旧权限逻辑;"
"优化 Web 端路由切换时的控制权限释放机制,解决权限滞留。",
"性能优化与组件迭代:完成路由组件拆分优化、精简冗余代码、优化加载逻辑,提升路由跳转速度;"
"修复 WebSocket 切换时序差导致的历史数据残留。",
"基础功能模块完善:完成系统基本设置模块迭代,新增「用户角色概览」「角色权限概览」;"
"完成电站地址功能接入,支持自定义修改场站地址。",
"文档沉淀:梳理 Web 端路径规划完整操作流程,编写标准化 SOP 操作文档,统一操作规范。",
"现场演示调试:配合机器展会演示调试与保障工作,确保现场演示顺利开展。",
]
for i, it in enumerate(items, 1):
add_numbered(doc, it)
add_h3(doc, "本周产出")
add_image(doc, "14_system.png", 2.6, "系统设置 — 用户/角色模块优化")
add_image(doc, "02_device_overview.png", 5.5, "设备总览 — 电站地址接入与多场站切换")
# ---------- 第 3 周 ----------
add_h2(doc, "第 3 周(8/15 – 8/21):视频日志改造 + 国际化 + 软著推进")
add_h3(doc, "工作主题")
add_p(doc, "完成视频/日志管理模块建设、iOS 适配指导、系统中英文国际化、APP 端优化及软著申报材料撰写。", indent_first=True)
add_h3(doc, "具体工作")
items = [
"视频管理模块开发:支持批量下载设备本地存储视频文件,将原有 Node 脚本实现的下载逻辑重构为 Java 接口,"
"统一后端技术栈。",
"日志管理模块开发:实现权限区分展示,支持管理员查看服务端运行日志,便于后续问题排查与系统运维。",
"iOS 适配指导与技术文档沉淀:协助指导 APP 苹果端相关功能实现,独立整理并输出 ios.md 技术文档,"
"统一调试规范与适配细节。",
"系统中英文国际化适配:完成平台核心业务界面的中英文双语切换功能开发,覆盖日常使用高频页面,"
"满足多语言使用场景。",
"APP 端功能优化:指导 APP 端完成视频推拉流控制功能开发与调试;优化无人机实时数据展示逻辑,"
"提升数据刷新实时性与页面展示效果。",
"软件著作权申报:结合平台现有功能、业务架构与技术实现,独立完成软著申报材料撰写,"
"梳理系统创新点、功能架构与应用场景。",
"AI 大模型版本升级:根据项目智能化迭代要求,将原有模型统一更新为 GPT-5.6 版本,"
"进一步提升平台智能化服务能力。",
]
for i, it in enumerate(items, 1):
add_numbered(doc, it)
add_h3(doc, "本周产出")
add_image(doc, "06_video.png", 5.5, "视频管理模块 — 批量下载 + 日志管理界面")
add_image(doc, "15_users.png", 4.0, "用户与角色管理 — 国际化覆盖")
# ---------- 第 4 周 ----------
add_h2(doc, "第 4 周(8/22 – 8/28):路由重构 + 设备参数编辑 + 定时任务")
add_h3(doc, "工作主题")
add_p(doc, "完成系统路由架构从一级到二级改造、设备参数编辑功能迭代开发与测试、定时任务功能落实。", indent_first=True)
add_h3(doc, "具体工作")
items = [
"路由架构整体优化升级:将原有一级路由改造为二级路由体系,梳理规整页面层级结构;"
"针对性修复更换路由框架带来的适配问题。",
"设备参数编辑功能迭代:完成 Web 端与 APP 端设备参数修改功能开发;新增授权机制管控参数修改权限,"
"Web 端可自定义配置设备参数可修改时长。",
"双端授权与权限控制:根据授权信息自动判断用户操作权限,实现参数编辑功能的可用性精准控制。",
"参数滑块联动与组件轻量化:实现参数滑块联动展示效果;对设备参数组件进行抽离重构,"
"新增 loading 加载状态,优化页面加载性能。",
"APP 端蓝牙模式适配:完成 APP 端蓝牙模式修改设备参数功能开发与测试,适配不同设备操作场景。",
"定时任务功能测试:完成 Web 端定时任务功能全流程测试,校验任务创建、执行、启停、周期运行等核心逻辑。",
"APP 端优化指导与测试验收:协助 APP 端完成扫码绑定设备、蓝牙/非蓝牙模式适配、"
"授权管控设备参数修改等核心功能优化与全面测试。",
]
for i, it in enumerate(items, 1):
add_numbered(doc, it)
add_h3(doc, "本周产出")
add_image(doc, "01_home.png", 5.5, "系统首页 — 二级路由重构后加载更顺畅")
add_image(doc, "03_device_status.png", 5.5, "设备状态详情 — 参数滑块 + 授权控制")
add_image(doc, "04_wayline.png", 5.0, "航线任务 — 二级路由结构下跳转清晰")
# ---------- 第 5 周 ----------
add_h2(doc, "第 5 周(8/29 – 8/31):全链路闭环测试 + 工单派发 + TodoList")
add_h3(doc, "工作主题")
add_p(doc, "完成系统全业务链路闭环测试、工单派发功能开发、TodoList 页面建设,APP 端收尾验证。", indent_first=True)
add_h3(doc, "具体工作")
items = [
"全业务链路闭环测试:完成告警、工单、任务全流程链路逻辑测试——告警触发后自动生成工单、"
"关联告警的工单完成后自动消除、设备异常可重新触发告警。",
"告警钉钉推送:支持各场站独立配置开启/关闭钉钉推送权限,实现告警消息灵活推送。",
"工单派发功能开发:新增平台工单手动派发逻辑,支持管理员将各类运维工单定向指派给指定用户,"
"完善工单分配管理机制。",
"设备参数配置功能测试:支持自定义配置设备轮胎增益系数、运行速度等核心参数,"
"页面配置逻辑与参数保存功能运行正常(待下位机联调收尾)。",
"TodoList 页面建设:完成平台 TodoList 页面搭建,统一录入待优化、待开发、待测试任务点,"
"实现任务可视化、条理化管理。",
"APP 端收尾:APP 端绝大部分测试点已完成验证,整体功能基本达标;"
"剩余约 10% 测试内容仍存在轻微问题,持续跟进排查与修复。",
]
for i, it in enumerate(items, 1):
add_numbered(doc, it)
add_h3(doc, "本周产出")
add_image(doc, "09_alerts.png", 5.5, "告警中心 — 钉钉推送 + 自动闭环")
add_image(doc, "12_workorder.png", 5.5, "工单任务 — 手动派发 + 全流程闭环")
add_image(doc, "05_robot_task.png", 4.5, "机器人任务 — 实时路径与规划路径展示")
add_page_break(doc)
# ============================================================
# 三、重点项目成果
# ============================================================
add_h1(doc, "三、重点项目成果")
add_h2(doc, "3.1 设备控制权限体系重构(核心项目)")
add_p(doc, "原「单用户单设备控制」模式存在多端抢占、权限残留、消息错乱等隐患,"
"本月将权限模型重构为「单设备单 Token 唯一占用」,从底层保证设备控制权的唯一性。",
indent_first=True, align="justify")
ach_rows = [
("权限模型", "单用户单设备", "单设备单 Token 唯一占用"),
("多端抢占", "存在冲突", "彻底解决"),
("权限残留", "偶发滞留", "路由切换即释放"),
("跨端测试", "未覆盖", "Web/APP 跨端 4 场景全闭环"),
("WS 连接", "多页面重复连接", "单页面单连接 + 自动销毁"),
("心跳堆积", "偶发", "已消除"),
]
add_data_table(doc, ["对比项", "重构前", "重构后"], ach_rows, widths=(1.8, 2.0, 2.5))
doc.add_paragraph()
add_h2(doc, "3.2 视频与日志管理模块(新建项目)")
add_p(doc, "原视频下载采用 Node 脚本实现,与平台 Java 后端技术栈不统一;日志管理缺失管理员视角。"
"本月将视频下载重构为 Java 接口,统一后端技术栈;新增日志管理模块,按权限区分展示。",
indent_first=True, align="justify")
add_bullet(doc, "视频管理:支持批量下载设备本地存储视频文件,由 Java 接口实现,统一后端技术栈。")
add_bullet(doc, "日志管理:支持管理员查看服务端运行日志,按权限区分展示,便于问题定位与运维排查。")
add_h2(doc, "3.3 路由架构二级改造(平台升级)")
add_p(doc, "为解决页面层级不清、跳转混乱的问题,本月完成路由从一级到二级架构的整体升级。",
indent_first=True, align="justify")
add_bullet(doc, "梳理页面层级结构,整体架构更清晰规范;")
add_bullet(doc, "重点优化设备总览、设备状态详情页面的路由跳转逻辑,解决跳转异常、定位不准等问题;")
add_bullet(doc, "页面访问体验与可维护性显著提升。")
add_h2(doc, "3.4 软件著作权申报")
add_p(doc, "本月独立完成软件著作权申报材料撰写,覆盖系统创新点、功能架构与应用场景,"
"并依据审核反馈持续完善。",
indent_first=True, align="justify")
ach2 = [
("软件名称", "光伏机器人环境感知服务平台"),
("软件简称", "光伏智能运维系统"),
("版本号", "V1.0"),
("源程序量", "约 53700 行"),
("主要功能", "10 大模块,701 字详述"),
("文档产出", "用户操作手册(13 章 / 16 张截图)+ 软著采集表 + SOP"),
]
add_kv_table(doc, ach2)
add_page_break(doc)
# ============================================================
# 四、代码与文档产出
# ============================================================
add_h1(doc, "四、代码与文档产出")
add_h2(doc, "4.1 月度代码提交概览")
git_rows = [
("8 月上旬", "中英文切换 / 二级路由 / 设备参数滑块 / 派单优化 / 推拉流", "17 次"),
("8 月中旬", "二级菜单 / 状态机解耦 / 文档产出 / iOS 适配 / 软著推进", "12 次"),
("8 月下旬", "MQTT 优化 / WS 时序 / 控制权限重构 / 路径联调", "13 次"),
("8 月底", "告警闭环 / 工单派发 / 钉钉推送 / TodoList / Bug 修复", "16 次"),
("合计", "—", "58 次"),
]
add_data_table(doc, ["时段", "主要方向", "提交次数"], git_rows, widths=(1.2, 4.6, 1.0))
doc.add_paragraph()
add_h2(doc, "4.2 主要文档清单")
add_bullet(doc, "《用户操作手册》——13 章 ~15 页,含 16 张页面截图(路径 / .workbuddy/gen_doc.py)")
add_bullet(doc, "《软件著作权采集表》——20 个字段全覆盖(路径 / 软著/采集表(已填写).doc)")
add_bullet(doc, "《SOP 操作文档》——Web 端路径规划完整操作流程,便于人员交接与业务落地")
add_bullet(doc, "《ios.md 技术文档》——iOS 端调试要点、适配细节、问题复盘")
add_bullet(doc, "《声网视频接入说明》——Agora 接入方式、Token 安全风险与改造建议")
add_bullet(doc, "《系统架构设计文档》——html 版,便于浏览与跨部门评审")
doc.add_paragraph()
add_h2(doc, "4.3 关键界面截图")
add_image(doc, "07_realtime.png", 5.5, "实时监控中心 — 设备控制 + 视频播放")
add_image(doc, "08_monitor.png", 5.5, "实时监控地图 — 规划路径与实时轨迹")
add_image(doc, "10_ai.png", 4.5, "AI 诊断分析 — GPT-5.6 模型支撑")
add_image(doc, "11_clean.png", 4.5, "清洗优化模块 — 业务模块适配")
add_image(doc, "13_report.png", 4.5, "报表中心 — 数据可视化")
add_image(doc, "16_roles.png", 4.5, "角色管理 — 权限精细化管控")
add_page_break(doc)
# ============================================================
# 五、工作总结与反思
# ============================================================
add_h1(doc, "五、工作总结与反思")
add_h2(doc, "5.1 本月做得好的方面")
good = [
"持续推进苏州算法联调:从 8 月初启动到 8 月底收尾,完整跑通路径规划全流程,"
"并完成现场演示保障,业务链路闭合度较高。",
"控制权限重构扎实:模型从设计、迁移到全场景测试均严格闭环,覆盖 Web/APP 双端 4 种跨端场景。",
"代码质量与可维护性提升:完成路由组件拆分、设备参数组件抽离、视频接口统一(Java 化),"
"为后续迭代打好基础。",
"文档与材料齐头并进:在迭代开发的同时,同步输出用户手册、软著材料、SOP 等关键文档,"
"沉淀团队知识资产。",
"跨端协同高效:与 APP 端保持紧密指导与测试验收节奏,确保双端业务逻辑统一、交互闭环。",
]
for g in good:
add_bullet(doc, g)
add_h2(doc, "5.2 待提升与反思")
todo = [
"设备参数配置模块:因下位机未完成全量测试,整体联调暂未完成,需在下月优先推进。",
"国际化覆盖:尚有约 1070 个 t() key 在中英文 locale 中缺失、69 个文件约 1403 行硬编码中文待处理,"
"需要分批推进。",
"APP 端收尾:仍有约 10% 测试点存在轻微问题,需持续跟进排查与修复。",
"工单自动派发:当前仅完成手动派发逻辑,自动派发策略仍需后续迭代。",
"二级路由后路径仍有抖动,地图地址接入在切换场站时偶发小问题,需进一步打磨。",
]
for t in todo:
add_bullet(doc, t)
add_page_break(doc)
# ============================================================
# 六、9 月工作计划
# ============================================================
add_h1(doc, "六、9 月工作计划")
add_p(doc, "结合本月遗留问题与项目下一阶段目标,初步拟定 9 月工作计划如下:", indent_first=True)
sep_rows = [
("设备参数全量联调", "高", "9 月上旬", "配合下位机完成设备参数配置模块全量测试闭环"),
("国际化深水区推进", "高", "9 月全月", "批量补齐约 1070 个 t() key 与 1403 行硬编码中文"),
("APP 端 10% 问题修复", "高", "9 月上旬", "完成 APP 端剩余测试点闭环,达成全量验收"),
("工单自动派发", "中", "9 月中旬", "上线自动派发策略,提升运维自动化效率"),
("视频流稳定性优化", "中", "9 月中旬", "声网重连、订阅回收、推拉流优化持续打磨"),
("软著申报推进", "中", "9 月", "根据审核意见持续完善软著材料"),
("TodoList 持续运营", "低", "9 月全月", "持续沉淀任务点,每周迭代"),
]
add_data_table(doc, ["工作计划", "优先级", "时间", "目标"], sep_rows, widths=(1.6, 0.8, 1.0, 2.9))
doc.add_paragraph()
add_p(doc, "以上为本人 2026 年 8 月工作月度报告的全部内容,请审阅。", indent_first=True, align="right",
space_after=2)
add_p(doc, "报告人:葛昀", indent_first=False, align="right", space_after=2)
add_p(doc, "日期:2026 年 9 月", indent_first=False, align="right", space_after=2)
# 保存
doc.save(OUTPUT_PATH)
print(f"OK: 生成成功 -> {OUTPUT_PATH}")
print(f"大小: {os.path.getsize(OUTPUT_PATH)} bytes")