基于Python + wxPython开发一个本地工作日志管理工具
作者:winfredzhang
背景
日常办公中,工作日志往往具有明显的重复性:例如每天需要记录“考勤”“订饭”,每周一需要记录“周会”“收周报”等固定事项。但实际记录时,又经常夹杂临时任务、请假、补充说明等内容。
如果完全手写,每天都要重复输入固定内容;如果只用 Excel,又不够便捷,查询、复制、统计都比较麻烦。因此,我使用 Python 和 wxPython 编写了一个桌面端工作日志程序,用来快速记录、查询、复制和导出工作日志。
项目核心文件为 work_log_app.py,数据保存在同目录下的 work_log_data.json 中。

目标
本程序的目标是做一个轻量、离线、方便使用的工作日志工具,主要功能包括:
- 按日期记录工作日志,自动显示星期。
- 支持每天固定事项,例如“考勤”“订饭”。
- 支持每周固定事项,例如周一“周会”“收周报”。
- 支持请假状态,并且请假时仍可填写临时事项。
- 支持常用词维护、模糊搜索和快速加入。
- 支持按日期查询、按事项关键词查询。
- 支持按年度、月度以日历形式统计记录情况。
- 支持复制全部日志或复制指定起止日期范围内的日志。
- 支持导出 Excel 文件。
- 支持 Python 运行和 exe 打包运行时的数据路径兼容。
方法
程序采用 wxPython 构建桌面界面,使用 JSON 保存本地数据,使用 Python 标准库生成 Excel 文件。
整体结构可以分为四层:
- 数据层:负责读取和保存
work_log_data.json。 - 工具函数层:负责日期、星期、格式化、排序、查询等通用逻辑。
- 导出层:负责将日志内容导出为
.xlsx文件。 - 界面层:使用
wx.Frame、wx.Notebook、wx.Panel等控件构建功能界面。
程序入口如下:
def main():
app = wx.App(False)
frame = WorkLogFrame()
frame.Show()
app.MainLoop()
其中 WorkLogFrame 是主窗口类,所有界面和事件逻辑都集中在这个类中。
过程
1. 数据文件路径处理
程序首先处理数据文件路径:
APP_DIR = Path(sys.executable).resolve().parent if getattr(sys, "frozen", False) else Path(__file__).resolve().parent DATA_FILE = APP_DIR / "work_log_data.json"
这段代码解决了一个很常见的问题:Python 直接运行时,数据文件应放在 .py 文件同目录;打包成 exe 后,数据文件应放在 exe 同目录。如果继续使用 __file__,打包后可能会指向临时解包目录,导致程序读不到原有记录。
2. 数据结构设计
日志数据使用 JSON 保存,结构清晰,便于维护:
{
"daily_tasks": ["考勤。", "订饭。"],
"weekly_tasks": {
"0": ["周会。", "收周报。"]
},
"common_words": ["考勤。", "订饭。", "请假"],
"entries": [
{
"date": "2026-06-03",
"tasks": ["考勤。", "订饭。", "编写工作日志程序。"]
}
]
}
其中:
daily_tasks表示每天默认事项。weekly_tasks表示每周固定事项,0代表周一。common_words表示常用词。entries表示实际日志记录。
读取数据时,程序会自动补齐缺失字段:
data.setdefault("daily_tasks", DEFAULT_DAILY_TASKS[:])
data.setdefault("weekly_tasks", dict(DEFAULT_WEEKLY_TASKS))
data.setdefault("entries", [])
data.setdefault("common_words", unique_items(generated_words))
这样即使后续程序增加了新字段,旧数据文件也可以继续兼容。
3. 日志格式化
日志复制时,需要生成类似下面的文本:
2026-06-03 周三 考勤。 订饭。 编写工作日志程序。
对应函数为:
def format_day_block(entry):
tasks = entry.get("tasks", [])
header = f"{entry['date']} {weekday_name(entry['date'])}"
if not tasks:
return header
return f"{header}\n" + "\n\n".join(tasks)
这里通过 weekday_name() 自动计算星期,通过空行分隔事项,方便直接复制到微信、文档或邮件中。
4. 主界面设计
程序使用 wx.Notebook 创建四个页签:
self.notebook.AddPage(self.record_panel, "记录") self.notebook.AddPage(self.query_panel, "查询") self.notebook.AddPage(self.stats_panel, "统计") self.notebook.AddPage(self.words_panel, "常用词")
四个页面分别负责:
- 记录:日常录入、保存、删除、复制、导出。
- 查询:按日期或事项关键词查询。
- 统计:按年度、月度生成日历视图。
- 常用词:编辑每天事项、周一事项和常用词。
5. 记录功能实现
记录页提供日期选择、前一天、后一天、请假、每日事项、每周事项、临时事项等控件。
切换日期时,会自动加载当天记录:
def set_selected_date(self, iso_date):
self.selected_date = iso_date
dt = datetime.strptime(iso_date, "%Y-%m-%d")
wx_dt = wx.DateTime(dt.day, dt.month - 1, dt.year)
self.date_picker.SetValue(wx_dt)
self.query_date_picker.SetValue(wx_dt)
self.copy_start_picker.SetValue(wx_dt)
self.copy_end_picker.SetValue(wx_dt)
self.load_entry_for_date(iso_date)
点击“前一天”“后一天”时,本质上是对日期做加减:
def move_selected_date(self, days):
new_date = date.fromisoformat(self.selected_date) + timedelta(days=days)
self.set_selected_date(new_date.isoformat())
保存日志时,程序会将勾选事项和临时事项合并:
def collect_tasks(self):
extras = normalize_lines(self.extra_text.GetValue())
if self.leave_check.GetValue():
return unique_items(["请假"] + extras)
tasks = []
...
tasks.extend(extras)
return unique_items(tasks)
这里有一个细节:请假并不是完全排他的状态。即使勾选“请假”,仍然可以继续填写临时事项,例如“请假”“处理邮件”“参加线上会议”等。
6. 常用词模糊搜索
记录页右侧有常用词列表,支持输入关键词过滤:
def refresh_common_words_ui(self):
all_words = self.data.get("common_words", [])
words = all_words
keyword = self.quick_word_filter.GetValue().strip()
if keyword:
words = [word for word in words if keyword in word]
self.quick_words_list.Set(words)
双击常用词后,会加入到临时事项中:
def on_quick_word_double_click(self, event):
index = self.quick_words_list.GetSelection()
if index != wx.NOT_FOUND:
self.add_quick_task(self.quick_words_list.GetString(index))
这种设计适合高频输入场景,减少重复打字。
7. 查询功能实现
查询页支持两种方式。
第一种是按日期查询:
def on_query_day(self, event):
iso_date = self.get_picker_iso(self.query_date_picker)
entry = entry_by_date(self.data["entries"], iso_date)
第二种是按事项关键词查询:
def on_query_task(self, event):
keyword = self.task_query_combo.GetValue().strip()
for entry in sorted_entries(self.data["entries"]):
hit_tasks = [task for task in entry.get("tasks", []) if keyword in task]
这可以快速回答“某件事在哪几天做过”这个问题。
8. 指定日期范围复制
除了复制全部日志,程序还支持复制某个起止日期范围内的内容:
def entries_between(entries, start_iso, end_iso):
start = min(start_iso, end_iso)
end = max(start_iso, end_iso)
return sorted_entries([entry for entry in entries if start <= entry["date"] <= end])
即使用户把结束日期选在开始日期前面,程序也会自动纠正范围。
9. 日历统计功能
统计页使用 wx.grid.Grid 构建月度日历视图:
self.calendar_grid = wx.grid.Grid(self.stats_panel) self.calendar_grid.CreateGrid(6, 7)
程序通过 calendar.Calendar().monthdatescalendar() 获取月历数据,然后根据日志状态设置单元格颜色:
- 红色:请假。
- 绿色:已记录。
- 白色:当月未记录。
- 灰色:非当前月份日期。
核心逻辑如下:
if "请假" in tasks:
value += "\n请假"
bg = wx.Colour(255, 205, 205)
else:
value += f"\n{len(tasks)}项"
bg = wx.Colour(220, 242, 220)
双击日历中的某一天,还可以直接跳转到记录页进行查看或修改。
10. Excel 导出
程序没有依赖 openpyxl,而是使用标准库 zipfile 手动生成 .xlsx 文件。
Excel 本质上是一个 ZIP 包,里面包含若干 XML 文件。程序构造了:
[Content_Types].xml_rels/.relsxl/workbook.xmlxl/_rels/workbook.xml.relsxl/worksheets/sheet1.xml
最终写入压缩包:
with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as zf:
for name, content in files.items():
zf.writestr(name, content)
这种方式的优点是不需要额外安装第三方 Excel 库,适合轻量级工具。
结果
最终完成的程序具备较完整的工作日志管理能力:
- 可以快速记录每天事项。
- 可以自动填充每日、每周固定事项。
- 可以处理请假和临时事项。
- 可以维护常用词,并支持模糊搜索。
- 可以查询某一天的日志。
- 可以查询某件事在哪些日期做过。
- 可以按月用日历方式查看记录情况。
- 可以复制全部日志或指定日期范围内的日志。
- 可以导出 Excel 文件。
- 可以兼容 Python 运行和 exe 打包运行。
程序数据保存在本地 JSON 文件中,不依赖网络,也不依赖数据库,适合个人办公使用。
总结
这个项目虽然规模不大,但涵盖了桌面应用开发中的多个典型问题:界面设计、事件绑定、本地数据持久化、日期处理、文本格式化、查询统计、Excel 导出以及 exe 打包后的路径兼容。
从实现角度看,wxPython 适合开发这类本地办公小工具;JSON 适合保存轻量级结构化数据;标准库生成 Excel 虽然代码量略多,但避免了额外依赖。
到此这篇关于基于Python + wxPython开发一个本地工作日志管理工具的文章就介绍到这了,更多相关Python工作日志管理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
